diff --git a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj index 082c0bdb4..608bf5866 100644 --- a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj @@ -27,6 +27,7 @@ + diff --git a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs index a352c9d16..f38109b16 100644 --- a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs @@ -22,6 +22,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin { @@ -31,7 +32,8 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin { internal static class CatAPI { private const string URL = "https://aws.random.cat"; - internal static async Task GetRandomCatURL(WebBrowser webBrowser) { + [ItemCanBeNull] + internal static async Task GetRandomCatURL([NotNull] WebBrowser webBrowser) { const string request = URL + "/meow"; WebBrowser.ObjectResponse response = await webBrowser.UrlGetToJsonObject(request).ConfigureAwait(false); diff --git a/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj b/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj index 5611453bf..083dc5825 100644 --- a/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj +++ b/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj @@ -28,6 +28,7 @@ + diff --git a/ArchiSteamFarm.Tests/Trading.cs b/ArchiSteamFarm.Tests/Trading.cs index f28b9c831..89a1d224f 100644 --- a/ArchiSteamFarm.Tests/Trading.cs +++ b/ArchiSteamFarm.Tests/Trading.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.Reflection; using ArchiSteamFarm.Json; +using JetBrains.Annotations; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace ArchiSteamFarm.Tests { @@ -318,6 +319,7 @@ namespace ArchiSteamFarm.Tests { return (bool) method.Invoke(null, new object[] { inventory, itemsToGive, itemsToReceive }); } + [NotNull] private static Steam.Asset CreateItem(ulong classID, uint amount = 1, uint realAppID = Steam.Asset.SteamAppID, Steam.Asset.EType type = Steam.Asset.EType.TradingCard) => new Steam.Asset(Steam.Asset.SteamAppID, Steam.Asset.SteamCommunityContextID, classID, amount, realAppID, type); } } diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index 2fa3e37fa..785cb2284 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -95,6 +95,7 @@ namespace ArchiSteamFarm { } } + [ItemCanBeNull] internal static async Task Update(bool updateOverride = false) { if (!SharedInfo.BuildInfo.CanUpdate || (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { return null; @@ -243,13 +244,6 @@ namespace ArchiSteamFarm { } StringComparer botsComparer = await Core.GetBotsComparer().ConfigureAwait(false); - - if (botsComparer == null) { - ArchiLogger.LogNullError(nameof(botsComparer)); - - return; - } - Bot.Init(botsComparer); // Ensure that we ask for a list of servers if we don't have any saved servers available diff --git a/ArchiSteamFarm/Access.cs b/ArchiSteamFarm/Access.cs index e245f380e..fe799d8df 100644 --- a/ArchiSteamFarm/Access.cs +++ b/ArchiSteamFarm/Access.cs @@ -29,7 +29,7 @@ namespace ArchiSteamFarm { private readonly Bot Bot; - internal Access(Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); + internal Access([NotNull] Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); [PublicAPI] public bool IsFamilySharing(ulong steamID) { diff --git a/ArchiSteamFarm/Actions.cs b/ArchiSteamFarm/Actions.cs index 2280531d2..9ce33607a 100644 --- a/ArchiSteamFarm/Actions.cs +++ b/ArchiSteamFarm/Actions.cs @@ -46,7 +46,7 @@ namespace ArchiSteamFarm { private bool ProcessingGiftsScheduled; private bool TradingScheduled; - internal Actions(Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); + internal Actions([NotNull] Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); public void Dispose() { // Those are objects that are always being created if constructor doesn't throw exception @@ -363,6 +363,7 @@ namespace ArchiSteamFarm { } } + [ItemNotNull] internal async Task GetTradingLock() { await TradingSemaphore.WaitAsync().ConfigureAwait(false); diff --git a/ArchiSteamFarm/ArchiHandler.cs b/ArchiSteamFarm/ArchiHandler.cs index aeb1f5e99..8497cdb34 100644 --- a/ArchiSteamFarm/ArchiHandler.cs +++ b/ArchiSteamFarm/ArchiHandler.cs @@ -47,7 +47,7 @@ namespace ArchiSteamFarm { internal DateTime LastPacketReceived { get; private set; } - internal ArchiHandler(ArchiLogger archiLogger, SteamUnifiedMessages steamUnifiedMessages) { + internal ArchiHandler([NotNull] ArchiLogger archiLogger, [NotNull] SteamUnifiedMessages steamUnifiedMessages) { if ((archiLogger == null) || (steamUnifiedMessages == null)) { throw new ArgumentNullException(nameof(archiLogger) + " || " + nameof(steamUnifiedMessages)); } @@ -674,7 +674,7 @@ namespace ArchiSteamFarm { public EPurchaseResultDetail PurchaseResultDetail { get; internal set; } public EResult Result { get; internal set; } - internal PurchaseResponseCallback(JobID jobID, CMsgClientPurchaseResponse msg) { + internal PurchaseResponseCallback([NotNull] JobID jobID, [NotNull] CMsgClientPurchaseResponse msg) { if ((jobID == null) || (msg == null)) { throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } @@ -740,7 +740,7 @@ namespace ArchiSteamFarm { internal sealed class PlayingSessionStateCallback : CallbackMsg { internal readonly bool PlayingBlocked; - internal PlayingSessionStateCallback(JobID jobID, CMsgClientPlayingSessionState msg) { + internal PlayingSessionStateCallback([NotNull] JobID jobID, [NotNull] CMsgClientPlayingSessionState msg) { if ((jobID == null) || (msg == null)) { throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } @@ -753,7 +753,7 @@ namespace ArchiSteamFarm { internal sealed class RedeemGuestPassResponseCallback : CallbackMsg { internal readonly EResult Result; - internal RedeemGuestPassResponseCallback(JobID jobID, CMsgClientRedeemGuestPassResponse msg) { + internal RedeemGuestPassResponseCallback([NotNull] JobID jobID, [NotNull] CMsgClientRedeemGuestPassResponse msg) { if ((jobID == null) || (msg == null)) { throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } @@ -766,7 +766,7 @@ namespace ArchiSteamFarm { internal sealed class SharedLibraryLockStatusCallback : CallbackMsg { internal readonly ulong LibraryLockedBySteamID; - internal SharedLibraryLockStatusCallback(JobID jobID, CMsgClientSharedLibraryLockStatus msg) { + internal SharedLibraryLockStatusCallback([NotNull] JobID jobID, [NotNull] CMsgClientSharedLibraryLockStatus msg) { if ((jobID == null) || (msg == null)) { throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } @@ -784,7 +784,7 @@ namespace ArchiSteamFarm { internal sealed class UserNotificationsCallback : CallbackMsg { internal readonly Dictionary Notifications; - internal UserNotificationsCallback(JobID jobID, CMsgClientUserNotifications msg) { + internal UserNotificationsCallback([NotNull] JobID jobID, [NotNull] CMsgClientUserNotifications msg) { if ((jobID == null) || (msg == null)) { throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } @@ -824,7 +824,7 @@ namespace ArchiSteamFarm { } } - internal UserNotificationsCallback(JobID jobID, CMsgClientItemAnnouncements msg) { + internal UserNotificationsCallback([NotNull] JobID jobID, [NotNull] CMsgClientItemAnnouncements msg) { if ((jobID == null) || (msg == null)) { throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } @@ -853,7 +853,7 @@ namespace ArchiSteamFarm { internal sealed class VanityURLChangedCallback : CallbackMsg { internal readonly string VanityURL; - internal VanityURLChangedCallback(JobID jobID, CMsgClientVanityURLChangedNotification msg) { + internal VanityURLChangedCallback([NotNull] JobID jobID, [NotNull] CMsgClientVanityURLChangedNotification msg) { if ((jobID == null) || (msg == null)) { throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index b67d1e442..e8f35d2a5 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -83,7 +83,7 @@ namespace ArchiSteamFarm { private ulong SteamID; private string VanityURL; - internal ArchiWebHandler(Bot bot) { + internal ArchiWebHandler([NotNull] Bot bot) { Bot = bot ?? throw new ArgumentNullException(nameof(bot)); CachedApiKey = new ArchiCacheable(ResolveApiKey, TimeSpan.FromHours(1)); @@ -98,6 +98,7 @@ namespace ArchiSteamFarm { WebBrowser.Dispose(); } + [ItemCanBeNull] [PublicAPI] public async Task GetAbsoluteProfileURL(bool waitForInitialization = true) { if (waitForInitialization && (SteamID == 0)) { @@ -1010,8 +1011,10 @@ namespace ArchiSteamFarm { return true; } + [NotNull] internal HttpClient GenerateDisposableHttpClient() => WebBrowser.GenerateDisposableHttpClient(); + [ItemCanBeNull] internal async Task> GenerateNewDiscoveryQueue() { const string request = "/explore/generatenewdiscoveryqueue"; @@ -1023,6 +1026,7 @@ namespace ArchiSteamFarm { return output?.Queue; } + [ItemCanBeNull] internal async Task> GetActiveTradeOffers() { (bool success, string steamApiKey) = await CachedApiKey.GetValue().ConfigureAwait(false); @@ -1159,6 +1163,7 @@ namespace ArchiSteamFarm { return result; } + [ItemCanBeNull] internal async Task> GetAppList() { KeyValue response = null; @@ -1224,6 +1229,7 @@ namespace ArchiSteamFarm { return await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request, false).ConfigureAwait(false); } + [ItemCanBeNull] internal async Task GetConfirmationDetails(string deviceID, string confirmationHash, uint time, MobileAuthenticator.Confirmation confirmation) { if (string.IsNullOrEmpty(deviceID) || string.IsNullOrEmpty(confirmationHash) || (time == 0) || (confirmation == null)) { Bot.ArchiLogger.LogNullError(nameof(deviceID) + " || " + nameof(confirmationHash) + " || " + nameof(time) + " || " + nameof(confirmation)); @@ -1280,6 +1286,7 @@ namespace ArchiSteamFarm { return await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request).ConfigureAwait(false); } + [ItemCanBeNull] internal async Task> GetDigitalGiftCards() { const string request = "/gifts"; HtmlDocument response = await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false); @@ -1323,6 +1330,7 @@ namespace ArchiSteamFarm { return await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false); } + [ItemCanBeNull] internal async Task> GetFamilySharingSteamIDs() { const string request = "/account/managedevices?l=english"; HtmlDocument htmlDocument = await UrlGetToHtmlDocumentWithSession(SteamStoreURL, request).ConfigureAwait(false); @@ -1367,6 +1375,7 @@ namespace ArchiSteamFarm { return await UrlGetToHtmlDocumentWithSession(SteamCommunityURL, request, false).ConfigureAwait(false); } + [ItemCanBeNull] [SuppressMessage("ReSharper", "FunctionComplexityOverflow")] internal async Task> GetInventory(ulong steamID = 0, uint appID = Steam.Asset.SteamAppID, uint contextID = Steam.Asset.SteamCommunityContextID, bool? tradable = null, IReadOnlyCollection wantedTypes = null, IReadOnlyCollection wantedRealAppIDs = null, IReadOnlyCollection<(uint AppID, Steam.Asset.EType Type)> wantedSets = null, IReadOnlyCollection<(uint AppID, Steam.Asset.EType Type)> skippedSets = null) { if ((appID == 0) || (contextID == 0)) { @@ -1495,6 +1504,7 @@ namespace ArchiSteamFarm { } } + [ItemCanBeNull] internal async Task> GetMyOwnedGames() { const string request = "/my/games?l=english&xml=1"; @@ -1537,6 +1547,7 @@ namespace ArchiSteamFarm { return result; } + [ItemCanBeNull] internal async Task> GetOwnedGames(ulong steamID) { if (steamID == 0) { Bot.ArchiLogger.LogNullError(nameof(steamID)); diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 71af9dfdf..6a9e2007b 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -114,16 +114,32 @@ namespace ArchiSteamFarm { private readonly SteamUser SteamUser; private readonly Trading Trading; + [NotNull] private string BotPath => Path.Combine(SharedInfo.ConfigDirectory, BotName); + + [NotNull] private string ConfigFilePath => BotPath + SharedInfo.ConfigExtension; + + [NotNull] private string DatabaseFilePath => BotPath + SharedInfo.DatabaseExtension; + + [NotNull] private string KeysToRedeemFilePath => BotPath + SharedInfo.KeysExtension; + + [NotNull] private string KeysToRedeemUnusedFilePath => KeysToRedeemFilePath + SharedInfo.KeysUnusedExtension; + + [NotNull] private string KeysToRedeemUsedFilePath => KeysToRedeemFilePath + SharedInfo.KeysUsedExtension; + + [NotNull] private string MobileAuthenticatorFilePath => BotPath + SharedInfo.MobileAuthenticatorExtension; + + [NotNull] private string SentryFilePath => BotPath + SharedInfo.SentryHashExtension; [JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamID))] + [NotNull] private string SSteamID => SteamID.ToString(); [JsonProperty] @@ -170,7 +186,7 @@ namespace ArchiSteamFarm { private string TwoFactorCode; private byte TwoFactorCodeFailures; - private Bot(string botName, BotConfig botConfig, BotDatabase botDatabase) { + private Bot([NotNull] string botName, [NotNull] BotConfig botConfig, [NotNull] BotDatabase botDatabase) { if (string.IsNullOrEmpty(botName) || (botConfig == null) || (botDatabase == null)) { throw new ArgumentNullException(nameof(botName) + " || " + nameof(botConfig) + " || " + nameof(botDatabase)); } @@ -588,8 +604,10 @@ namespace ArchiSteamFarm { return result; } + [ItemCanBeNull] internal async Task> GetMarketableAppIDs() => await ArchiWebHandler.GetAppList().ConfigureAwait(false); + [ItemCanBeNull] internal async Task AppIDs)>> GetPackagesData(IReadOnlyCollection packageIDs) { if ((packageIDs == null) || (packageIDs.Count == 0)) { ArchiLogger.LogNullError(nameof(packageIDs)); @@ -1293,6 +1311,7 @@ namespace ArchiSteamFarm { return message.Replace("\\", "\\\\").Replace("[", "\\["); } + [ItemCanBeNull] private async Task> GetKeysFromFile(string filePath) { if (string.IsNullOrEmpty(filePath)) { ArchiLogger.LogNullError(nameof(filePath)); diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index 9a2626a2c..6dab78aef 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -229,6 +229,7 @@ namespace ArchiSteamFarm { private bool ShouldSerializeSensitiveDetails = true; [JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamMasterClanID), Required = Required.DisallowNull)] + [NotNull] private string SSteamMasterClanID { get => SteamMasterClanID.ToString(); @@ -297,6 +298,7 @@ namespace ArchiSteamFarm { return TradingPreferences <= ETradingPreferences.All ? (true, null) : (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(TradingPreferences), TradingPreferences)); } + [ItemCanBeNull] internal static async Task Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); diff --git a/ArchiSteamFarm/BotDatabase.cs b/ArchiSteamFarm/BotDatabase.cs index 80a4b8359..4a4153e53 100644 --- a/ArchiSteamFarm/BotDatabase.cs +++ b/ArchiSteamFarm/BotDatabase.cs @@ -27,6 +27,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using ArchiSteamFarm.Collections; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm { @@ -63,7 +64,7 @@ namespace ArchiSteamFarm { private bool ReadOnly; // This constructor is used when creating new database - private BotDatabase(string filePath) { + private BotDatabase([NotNull] string filePath) { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException(nameof(filePath)); } @@ -137,6 +138,7 @@ namespace ArchiSteamFarm { } } + [ItemCanBeNull] internal static async Task CreateOrLoad(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index 64f7fe3cf..4aed6fce9 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -32,6 +32,7 @@ using System.Threading.Tasks; using ArchiSteamFarm.Collections; using ArchiSteamFarm.Localization; using HtmlAgilityPack; +using JetBrains.Annotations; using Newtonsoft.Json; using SteamKit2; @@ -80,7 +81,7 @@ namespace ArchiSteamFarm { private bool PermanentlyPaused; private bool ShouldResumeFarming = true; - internal CardsFarmer(Bot bot) { + internal CardsFarmer([NotNull] Bot bot) { Bot = bot ?? throw new ArgumentNullException(nameof(bot)); if (Program.GlobalConfig.IdleFarmingPeriod > 0) { @@ -1004,6 +1005,12 @@ namespace ArchiSteamFarm { } private async Task IsPlayableGame(Game game) { + if (game == null) { + Bot.ArchiLogger.LogNullError(nameof(game)); + + return false; + } + (uint playableAppID, DateTime ignoredUntil) = await Bot.GetAppDataForIdling(game.AppID, game.HoursPlayed).ConfigureAwait(false); if (playableAppID == 0) { @@ -1182,7 +1189,7 @@ namespace ArchiSteamFarm { internal uint PlayableAppID { get; set; } - internal Game(uint appID, string gameName, float hoursPlayed, ushort cardsRemaining, byte badgeLevel) { + internal Game(uint appID, [NotNull] string gameName, float hoursPlayed, ushort cardsRemaining, byte badgeLevel) { if ((appID == 0) || string.IsNullOrEmpty(gameName) || (hoursPlayed < 0) || (cardsRemaining == 0)) { throw new ArgumentOutOfRangeException(nameof(appID) + " || " + nameof(gameName) + " || " + nameof(hoursPlayed) + " || " + nameof(cardsRemaining)); } diff --git a/ArchiSteamFarm/Collections/ConcurrentHashSet.cs b/ArchiSteamFarm/Collections/ConcurrentHashSet.cs index 0c7f128f1..692f7cc69 100644 --- a/ArchiSteamFarm/Collections/ConcurrentHashSet.cs +++ b/ArchiSteamFarm/Collections/ConcurrentHashSet.cs @@ -22,6 +22,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using JetBrains.Annotations; @@ -34,7 +35,10 @@ namespace ArchiSteamFarm.Collections { public bool Add(T item) => BackingCollection.TryAdd(item, true); public void Clear() => BackingCollection.Clear(); + + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] public bool Contains(T item) => BackingCollection.ContainsKey(item); + public void CopyTo(T[] array, int arrayIndex) => BackingCollection.Keys.CopyTo(array, arrayIndex); public void ExceptWith(IEnumerable other) { @@ -83,6 +87,7 @@ namespace ArchiSteamFarm.Collections { return otherSet.Any(Contains); } + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] public bool Remove(T item) => BackingCollection.TryRemove(item, out _); public bool SetEquals(IEnumerable other) { @@ -111,19 +116,21 @@ namespace ArchiSteamFarm.Collections { } } + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] void ICollection.Add(T item) => Add(item); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); // We use Count() and not Any() because we must ensure full loop pass [PublicAPI] - public bool AddRange(IEnumerable items) => items.Count(Add) > 0; + public bool AddRange([NotNull] IEnumerable items) => items.Count(Add) > 0; // We use Count() and not Any() because we must ensure full loop pass [PublicAPI] - public bool RemoveRange(IEnumerable items) => items.Count(Remove) > 0; + public bool RemoveRange([NotNull] IEnumerable items) => items.Count(Remove) > 0; [PublicAPI] - public bool ReplaceIfNeededWith(IReadOnlyCollection other) { + public bool ReplaceIfNeededWith([NotNull] IReadOnlyCollection other) { if (SetEquals(other)) { return false; } @@ -134,7 +141,7 @@ namespace ArchiSteamFarm.Collections { } [PublicAPI] - public void ReplaceWith(IEnumerable other) { + public void ReplaceWith([NotNull] IEnumerable other) { BackingCollection.Clear(); foreach (T item in other) { diff --git a/ArchiSteamFarm/Collections/ConcurrentSortedHashSet.cs b/ArchiSteamFarm/Collections/ConcurrentSortedHashSet.cs index 0c907bcb6..369486071 100644 --- a/ArchiSteamFarm/Collections/ConcurrentSortedHashSet.cs +++ b/ArchiSteamFarm/Collections/ConcurrentSortedHashSet.cs @@ -22,7 +22,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Threading; +using JetBrains.Annotations; namespace ArchiSteamFarm.Collections { internal sealed class ConcurrentSortedHashSet : IDisposable, IReadOnlyCollection, ISet { @@ -197,10 +199,12 @@ namespace ArchiSteamFarm.Collections { } } + [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] void ICollection.Add(T item) => Add(item); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - internal void ReplaceWith(IEnumerable other) { + internal void ReplaceWith([NotNull] IEnumerable other) { CollectionSemaphore.Wait(); try { @@ -222,7 +226,7 @@ namespace ArchiSteamFarm.Collections { object IEnumerator.Current => Current; - internal ConcurrentEnumerator(IReadOnlyCollection collection, SemaphoreSlim semaphore) { + internal ConcurrentEnumerator([NotNull] IReadOnlyCollection collection, [NotNull] SemaphoreSlim semaphore) { if ((collection == null) || (semaphore == null)) { throw new ArgumentNullException(nameof(collection) + " || " + nameof(semaphore)); } diff --git a/ArchiSteamFarm/Commands.cs b/ArchiSteamFarm/Commands.cs index 4e39e2634..95f41790b 100644 --- a/ArchiSteamFarm/Commands.cs +++ b/ArchiSteamFarm/Commands.cs @@ -36,7 +36,7 @@ namespace ArchiSteamFarm { private readonly Bot Bot; private readonly Dictionary CachedGamesOwned = new Dictionary(); - internal Commands(Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); + internal Commands([NotNull] Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); [PublicAPI] public static string FormatBotResponse(string response, string botName) { @@ -398,6 +398,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(!string.IsNullOrEmpty(token) ? string.Format(Strings.BotAuthenticatorToken, token) : Strings.WarningFailed); } + [ItemCanBeNull] private static async Task Response2FA(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -442,6 +443,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(result ? Strings.Success : Strings.WarningFailed); } + [ItemCanBeNull] private static async Task Response2FAConfirm(ulong steamID, string botNames, bool confirm) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -543,6 +545,7 @@ namespace ArchiSteamFarm { return await ResponseAddLicense(steamID, gamesToRedeem).ConfigureAwait(false); } + [ItemCanBeNull] private static async Task ResponseAddLicense(ulong steamID, string botNames, string targetGameIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetGameIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetGameIDs)); @@ -591,6 +594,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponseAdvancedLoot(ulong steamID, string botNames, string appID, string contextID) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(appID) || string.IsNullOrEmpty(contextID)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(appID) + " || " + nameof(contextID)); @@ -673,6 +677,7 @@ namespace ArchiSteamFarm { return await ResponseRedeem(steamID, keys, redeemFlags).ConfigureAwait(false); } + [ItemCanBeNull] private static async Task ResponseAdvancedRedeem(ulong steamID, string botNames, string options, string keys) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(options) || string.IsNullOrEmpty(keys)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(options) + " || " + nameof(keys)); @@ -787,6 +792,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(blacklist.Count > 0 ? string.Join(", ", blacklist) : string.Format(Strings.ErrorIsEmpty, nameof(blacklist))); } + [ItemCanBeNull] private static async Task ResponseBlacklist(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -839,6 +845,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseBlacklistAdd(ulong steamID, string botNames, string targetSteamIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetSteamIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetSteamIDs)); @@ -891,6 +898,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseBlacklistRemove(ulong steamID, string botNames, string targetSteamIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetSteamIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetSteamIDs)); @@ -951,6 +959,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseFarm(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -997,6 +1006,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(idleBlacklist.Count > 0 ? string.Join(", ", idleBlacklist) : string.Format(Strings.ErrorIsEmpty, nameof(idleBlacklist))); } + [ItemCanBeNull] private static async Task ResponseIdleBlacklist(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -1049,6 +1059,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseIdleBlacklistAdd(ulong steamID, string botNames, string targetAppIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetAppIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetAppIDs)); @@ -1101,6 +1112,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseIdleBlacklistRemove(ulong steamID, string botNames, string targetAppIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetAppIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetAppIDs)); @@ -1137,6 +1149,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(idleQueue.Count > 0 ? string.Join(", ", idleQueue) : string.Format(Strings.ErrorIsEmpty, nameof(idleQueue))); } + [ItemCanBeNull] private static async Task ResponseIdleQueue(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -1189,6 +1202,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseIdleQueueAdd(ulong steamID, string botNames, string targetAppIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetAppIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetAppIDs)); @@ -1241,6 +1255,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseIdleQueueRemove(ulong steamID, string botNames, string targetAppIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetAppIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetAppIDs)); @@ -1285,6 +1300,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseInput(ulong steamID, string botNames, string propertyName, string inputValue) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(propertyName) || string.IsNullOrEmpty(inputValue)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(propertyName) + " || " + nameof(inputValue)); @@ -1325,6 +1341,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(level.HasValue ? string.Format(Strings.BotLevel, level.Value) : Strings.WarningFailed); } + [ItemCanBeNull] private static async Task ResponseLevel(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -1369,6 +1386,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponseLoot(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -1429,6 +1447,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponseLootByRealAppIDs(ulong steamID, string botNames, string realAppIDsText) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(realAppIDsText)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(realAppIDsText)); @@ -1469,6 +1488,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseNickname(ulong steamID, string botNames, string nickname) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(nickname)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(nickname)); @@ -1576,6 +1596,7 @@ namespace ArchiSteamFarm { return (response.Length > 0 ? response.ToString() : FormatBotResponse(string.Format(Strings.BotNotOwnedYet, query)), ownedGameIDs); } + [ItemCanBeNull] private static async Task ResponseOwns(ulong steamID, string botNames, string query) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(query)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(query)); @@ -1631,6 +1652,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(string.Join(", ", encryptedPasswords.Where(kv => !string.IsNullOrEmpty(kv.Value)).Select(kv => string.Format(Strings.BotEncryptedPassword, kv.Key, kv.Value)))); } + [ItemCanBeNull] private static async Task ResponsePassword(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -1677,6 +1699,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponsePause(ulong steamID, string botNames, bool permanent, string resumeInSecondsText = null) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -1762,6 +1785,7 @@ namespace ArchiSteamFarm { return await ResponsePlay(steamID, gamesToPlay, gameName.ToString()).ConfigureAwait(false); } + [ItemCanBeNull] private static async Task ResponsePlay(ulong steamID, string botNames, string targetGameIDs) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(targetGameIDs)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(targetGameIDs)); @@ -1912,6 +1936,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(await Bot.ArchiWebHandler.ChangePrivacySettings(userPrivacy).ConfigureAwait(false) ? Strings.Success : Strings.WarningFailed); } + [ItemCanBeNull] private static async Task ResponsePrivacy(ulong steamID, string botNames, string privacySettingsText) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(privacySettingsText)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(privacySettingsText)); @@ -2140,6 +2165,7 @@ namespace ArchiSteamFarm { return response.Length > 0 ? response.ToString() : null; } + [ItemCanBeNull] private static async Task ResponseRedeem(ulong steamID, string botNames, string keys, ERedeemFlags redeemFlags = ERedeemFlags.None) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(keys)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(keys)); @@ -2192,6 +2218,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponseResume(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -2228,6 +2255,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponseStart(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -2308,6 +2336,7 @@ namespace ArchiSteamFarm { return (FormatBotResponse(string.Format(Strings.BotStatusIdling, soloGame.AppID, soloGame.GameName, soloGame.CardsRemaining, Bot.CardsFarmer.GamesToFarm.Count, Bot.CardsFarmer.GamesToFarm.Sum(game => game.CardsRemaining), Bot.CardsFarmer.TimeRemaining.ToHumanReadable())), Bot); } + [ItemCanBeNull] private static async Task ResponseStatus(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -2352,6 +2381,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponseStop(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -2408,6 +2438,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(success ? output : string.Format(Strings.WarningFailedWithError, output)); } + [ItemCanBeNull] private static async Task ResponseTransfer(ulong steamID, string botNames, string botNameTo) { if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(botNameTo)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(botNameTo)); @@ -2574,6 +2605,7 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.Done); } + [ItemCanBeNull] private static async Task ResponseUnpackBoosters(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); @@ -2634,6 +2666,7 @@ namespace ArchiSteamFarm { return !Bot.IsConnectedAndLoggedOn ? FormatBotResponse(Strings.BotNotConnected) : FormatBotResponse(Bot.WalletCurrency != ECurrencyCode.Invalid ? string.Format(Strings.BotWalletBalance, Bot.WalletBalance / 100.0, Bot.WalletCurrency.ToString()) : Strings.BotHasNoWallet); } + [ItemCanBeNull] private static async Task ResponseWalletBalance(ulong steamID, string botNames) { if ((steamID == 0) || string.IsNullOrEmpty(botNames)) { ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames)); diff --git a/ArchiSteamFarm/GitHub.cs b/ArchiSteamFarm/GitHub.cs index de5273e2e..cd75fe2f6 100644 --- a/ArchiSteamFarm/GitHub.cs +++ b/ArchiSteamFarm/GitHub.cs @@ -25,6 +25,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading.Tasks; +using JetBrains.Annotations; using Markdig; using Markdig.Renderers; using Markdig.Syntax; @@ -33,6 +34,7 @@ using Newtonsoft.Json; namespace ArchiSteamFarm { internal static class GitHub { + [ItemCanBeNull] internal static async Task GetLatestRelease(bool stable = true) { string releaseURL = SharedInfo.GithubReleaseURL + (stable ? "/latest" : "?per_page=1"); @@ -45,6 +47,7 @@ namespace ArchiSteamFarm { return response?.FirstOrDefault(); } + [ItemCanBeNull] internal static async Task GetRelease(string version) { if (string.IsNullOrEmpty(version)) { ASF.ArchiLogger.LogNullError(nameof(version)); @@ -55,6 +58,7 @@ namespace ArchiSteamFarm { return await GetReleaseFromURL(SharedInfo.GithubReleaseURL + "/tags/" + version).ConfigureAwait(false); } + [ItemCanBeNull] internal static async Task> GetReleases(byte count) { if (count == 0) { ASF.ArchiLogger.LogNullError(nameof(count)); @@ -86,6 +90,7 @@ namespace ArchiSteamFarm { return result; } + [ItemCanBeNull] private static async Task GetReleaseFromURL(string releaseURL) { if (string.IsNullOrEmpty(nameof(releaseURL))) { ASF.ArchiLogger.LogNullError(nameof(releaseURL)); @@ -98,6 +103,7 @@ namespace ArchiSteamFarm { return objectResponse?.Content; } + [ItemCanBeNull] private static async Task> GetReleasesFromURL(string releaseURL) { if (string.IsNullOrEmpty(nameof(releaseURL))) { ASF.ArchiLogger.LogNullError(nameof(releaseURL)); diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs index 070a63abf..e7ffbb147 100644 --- a/ArchiSteamFarm/GlobalConfig.cs +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -219,6 +219,7 @@ namespace ArchiSteamFarm { private bool ShouldSerializeSensitiveDetails = true; [JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamOwnerID), Required = Required.DisallowNull)] + [NotNull] private string SSteamOwnerID { get => SteamOwnerID.ToString(); @@ -261,12 +262,14 @@ namespace ArchiSteamFarm { return Enum.IsDefined(typeof(EUpdateChannel), UpdateChannel) ? (true, null) : (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(UpdateChannel), UpdateChannel)); } + [NotNull] internal static GlobalConfig Create() => new GlobalConfig { ShouldSerializeEverything = false, ShouldSerializeSensitiveDetails = false }; + [ItemCanBeNull] internal static async Task Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); diff --git a/ArchiSteamFarm/GlobalDatabase.cs b/ArchiSteamFarm/GlobalDatabase.cs index da2319217..1d2eadd76 100644 --- a/ArchiSteamFarm/GlobalDatabase.cs +++ b/ArchiSteamFarm/GlobalDatabase.cs @@ -27,6 +27,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using ArchiSteamFarm.SteamKit2; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm { @@ -49,7 +50,7 @@ namespace ArchiSteamFarm { private string FilePath; // This constructor is used when creating new database - private GlobalDatabase(string filePath) : this() { + private GlobalDatabase([NotNull] string filePath) : this() { if (string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException(nameof(filePath)); } @@ -69,6 +70,7 @@ namespace ArchiSteamFarm { PackagesRefreshSemaphore.Dispose(); } + [ItemCanBeNull] internal static async Task CreateOrLoad(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); diff --git a/ArchiSteamFarm/Helpers/ArchiCacheable.cs b/ArchiSteamFarm/Helpers/ArchiCacheable.cs index 38beda34b..71d7850cf 100644 --- a/ArchiSteamFarm/Helpers/ArchiCacheable.cs +++ b/ArchiSteamFarm/Helpers/ArchiCacheable.cs @@ -41,7 +41,7 @@ namespace ArchiSteamFarm.Helpers { private T InitializedValue; private Timer MaintenanceTimer; - internal ArchiCacheable(Func> resolveFunction, TimeSpan? cacheLifetime = null) { + internal ArchiCacheable([NotNull] Func> resolveFunction, TimeSpan? cacheLifetime = null) { ResolveFunction = resolveFunction ?? throw new ArgumentNullException(nameof(resolveFunction)); CacheLifetime = cacheLifetime ?? Timeout.InfiniteTimeSpan; } diff --git a/ArchiSteamFarm/Helpers/SemaphoreLock.cs b/ArchiSteamFarm/Helpers/SemaphoreLock.cs index aaa684c30..6821dbed6 100644 --- a/ArchiSteamFarm/Helpers/SemaphoreLock.cs +++ b/ArchiSteamFarm/Helpers/SemaphoreLock.cs @@ -21,12 +21,13 @@ using System; using System.Threading; +using JetBrains.Annotations; namespace ArchiSteamFarm.Helpers { internal sealed class SemaphoreLock : IDisposable { private readonly SemaphoreSlim Semaphore; - internal SemaphoreLock(SemaphoreSlim semaphore) => Semaphore = semaphore ?? throw new ArgumentNullException(nameof(semaphore)); + internal SemaphoreLock([NotNull] SemaphoreSlim semaphore) => Semaphore = semaphore ?? throw new ArgumentNullException(nameof(semaphore)); public void Dispose() => Semaphore.Release(); } diff --git a/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs b/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs index 171984ff2..ff5f4a508 100644 --- a/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs +++ b/ArchiSteamFarm/IPC/Middleware/ApiAuthenticationMiddleware.cs @@ -52,7 +52,7 @@ namespace ArchiSteamFarm.IPC.Middleware { private readonly RequestDelegate Next; - public ApiAuthenticationMiddleware(RequestDelegate next) => Next = next ?? throw new ArgumentNullException(nameof(next)); + public ApiAuthenticationMiddleware([NotNull] RequestDelegate next) => Next = next ?? throw new ArgumentNullException(nameof(next)); [PublicAPI] public async Task InvokeAsync(HttpContext context) { diff --git a/ArchiSteamFarm/IPC/Responses/ASFResponse.cs b/ArchiSteamFarm/IPC/Responses/ASFResponse.cs index 499d8c940..70060d1d8 100644 --- a/ArchiSteamFarm/IPC/Responses/ASFResponse.cs +++ b/ArchiSteamFarm/IPC/Responses/ASFResponse.cs @@ -21,6 +21,7 @@ using System; using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm.IPC.Responses { @@ -60,7 +61,7 @@ namespace ArchiSteamFarm.IPC.Responses { [Required] public readonly Version Version; - internal ASFResponse(string buildVariant, GlobalConfig globalConfig, uint memoryUsage, DateTime processStartTime, Version version) { + internal ASFResponse([NotNull] string buildVariant, [NotNull] GlobalConfig globalConfig, uint memoryUsage, DateTime processStartTime, [NotNull] Version version) { if (string.IsNullOrEmpty(buildVariant) || (globalConfig == null) || (memoryUsage == 0) || (processStartTime == DateTime.MinValue) || (version == null)) { throw new ArgumentNullException(nameof(buildVariant) + " || " + nameof(globalConfig) + " || " + nameof(memoryUsage) + " || " + nameof(processStartTime) + " || " + nameof(version)); } diff --git a/ArchiSteamFarm/IPC/Responses/GitHubReleaseResponse.cs b/ArchiSteamFarm/IPC/Responses/GitHubReleaseResponse.cs index b9007995f..f33d1dcea 100644 --- a/ArchiSteamFarm/IPC/Responses/GitHubReleaseResponse.cs +++ b/ArchiSteamFarm/IPC/Responses/GitHubReleaseResponse.cs @@ -21,6 +21,7 @@ using System; using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm.IPC.Responses { @@ -53,7 +54,7 @@ namespace ArchiSteamFarm.IPC.Responses { [Required] public readonly string Version; - internal GitHubReleaseResponse(GitHub.ReleaseResponse releaseResponse) { + internal GitHubReleaseResponse([NotNull] GitHub.ReleaseResponse releaseResponse) { if (releaseResponse == null) { throw new ArgumentNullException(nameof(releaseResponse)); } diff --git a/ArchiSteamFarm/IPC/Responses/TypeResponse.cs b/ArchiSteamFarm/IPC/Responses/TypeResponse.cs index 0e3f7c0d4..e494ae642 100644 --- a/ArchiSteamFarm/IPC/Responses/TypeResponse.cs +++ b/ArchiSteamFarm/IPC/Responses/TypeResponse.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm.IPC.Responses { @@ -45,7 +46,7 @@ namespace ArchiSteamFarm.IPC.Responses { [Required] public readonly TypeProperties Properties; - internal TypeResponse(Dictionary body, TypeProperties properties) { + internal TypeResponse([NotNull] Dictionary body, [NotNull] TypeProperties properties) { if ((body == null) || (properties == null)) { throw new ArgumentNullException(nameof(body) + " || " + nameof(properties)); } diff --git a/ArchiSteamFarm/IPC/Startup.cs b/ArchiSteamFarm/IPC/Startup.cs index 8341f3288..ca1df05fa 100644 --- a/ArchiSteamFarm/IPC/Startup.cs +++ b/ArchiSteamFarm/IPC/Startup.cs @@ -22,6 +22,7 @@ using System; using System.IO; using ArchiSteamFarm.IPC.Middleware; +using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; @@ -36,7 +37,7 @@ namespace ArchiSteamFarm.IPC { internal sealed class Startup { private readonly IConfiguration Configuration; - public Startup(IConfiguration configuration) => Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + public Startup([NotNull] IConfiguration configuration) => Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if ((app == null) || (env == null)) { diff --git a/ArchiSteamFarm/Json/Steam.cs b/ArchiSteamFarm/Json/Steam.cs index 448959f63..bb8c17aac 100644 --- a/ArchiSteamFarm/Json/Steam.cs +++ b/ArchiSteamFarm/Json/Steam.cs @@ -64,6 +64,7 @@ namespace ArchiSteamFarm.Json { public EType Type { get; internal set; } [JsonProperty(PropertyName = "amount", Required = Required.Always)] + [NotNull] private string AmountText { get => Amount.ToString(); @@ -85,6 +86,7 @@ namespace ArchiSteamFarm.Json { } [JsonProperty(PropertyName = "assetid", Required = Required.DisallowNull)] + [NotNull] private string AssetIDText { get => AssetID.ToString(); @@ -106,6 +108,7 @@ namespace ArchiSteamFarm.Json { } [JsonProperty(PropertyName = "classid", Required = Required.DisallowNull)] + [NotNull] private string ClassIDText { get => ClassID.ToString(); @@ -125,6 +128,7 @@ namespace ArchiSteamFarm.Json { } [JsonProperty(PropertyName = "contextid", Required = Required.DisallowNull)] + [NotNull] private string ContextIDText { get => ContextID.ToString(); @@ -146,6 +150,7 @@ namespace ArchiSteamFarm.Json { } [JsonProperty(PropertyName = "id", Required = Required.DisallowNull)] + [NotNull] private string IDText { get => AssetIDText; set => AssetIDText = value; @@ -555,7 +560,7 @@ namespace ArchiSteamFarm.Json { internal readonly PrivacySettings Settings; // Constructed from privacy change request - internal UserPrivacy(PrivacySettings settings, ECommentPermission commentPermission) { + internal UserPrivacy([NotNull] PrivacySettings settings, ECommentPermission commentPermission) { Settings = settings ?? throw new ArgumentNullException(nameof(settings)); CommentPermission = commentPermission; } diff --git a/ArchiSteamFarm/MobileAuthenticator.cs b/ArchiSteamFarm/MobileAuthenticator.cs index 6665d481a..188ddd564 100644 --- a/ArchiSteamFarm/MobileAuthenticator.cs +++ b/ArchiSteamFarm/MobileAuthenticator.cs @@ -29,6 +29,7 @@ using System.Threading.Tasks; using ArchiSteamFarm.Json; using ArchiSteamFarm.Localization; using HtmlAgilityPack; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm { @@ -92,6 +93,7 @@ namespace ArchiSteamFarm { return GenerateTokenForTime(time); } + [ItemCanBeNull] internal async Task GetConfirmationDetails(Confirmation confirmation) { if (confirmation == null) { Bot.ArchiLogger.LogNullError(nameof(confirmation)); @@ -126,6 +128,7 @@ namespace ArchiSteamFarm { return response?.Success == true ? response : null; } + [ItemCanBeNull] internal async Task> GetConfirmations(Steam.ConfirmationDetails.EType acceptedType = Steam.ConfirmationDetails.EType.Unknown) { if (!HasValidDeviceID) { Bot.ArchiLogger.LogGenericError(Strings.ErrorMobileAuthenticatorInvalidDeviceID); @@ -275,7 +278,7 @@ namespace ArchiSteamFarm { return true; } - internal void Init(Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); + internal void Init([NotNull] Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); internal static bool IsValidDeviceID(string deviceID) { if (string.IsNullOrEmpty(deviceID)) { diff --git a/ArchiSteamFarm/NLog/ArchiLogger.cs b/ArchiSteamFarm/NLog/ArchiLogger.cs index 6d9f1a891..f353e6edf 100644 --- a/ArchiSteamFarm/NLog/ArchiLogger.cs +++ b/ArchiSteamFarm/NLog/ArchiLogger.cs @@ -31,7 +31,7 @@ namespace ArchiSteamFarm.NLog { public sealed class ArchiLogger { private readonly Logger Logger; - public ArchiLogger(string name) { + public ArchiLogger([NotNull] string name) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } diff --git a/ArchiSteamFarm/NLog/HistoryTarget.cs b/ArchiSteamFarm/NLog/HistoryTarget.cs index 97f4c7e51..d4ddcf01a 100644 --- a/ArchiSteamFarm/NLog/HistoryTarget.cs +++ b/ArchiSteamFarm/NLog/HistoryTarget.cs @@ -80,7 +80,7 @@ namespace ArchiSteamFarm.NLog { internal sealed class NewHistoryEntryArgs : EventArgs { internal readonly string Message; - internal NewHistoryEntryArgs(string message) => Message = message ?? throw new ArgumentNullException(nameof(message)); + internal NewHistoryEntryArgs([NotNull] string message) => Message = message ?? throw new ArgumentNullException(nameof(message)); } } } diff --git a/ArchiSteamFarm/OS.cs b/ArchiSteamFarm/OS.cs index 46af0fa1a..f2f1f52d2 100644 --- a/ArchiSteamFarm/OS.cs +++ b/ArchiSteamFarm/OS.cs @@ -24,10 +24,13 @@ using System.IO; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using ArchiSteamFarm.Localization; +using JetBrains.Annotations; namespace ArchiSteamFarm { internal static class OS { internal static bool IsUnix => RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + + [NotNull] internal static string Variant => RuntimeInformation.OSDescription.Trim(); internal static void Init(bool systemRequired, GlobalConfig.EOptimizationMode optimizationMode) { diff --git a/ArchiSteamFarm/Plugins/Core.cs b/ArchiSteamFarm/Plugins/Core.cs index 32ea9a36c..c8e6dfe22 100644 --- a/ArchiSteamFarm/Plugins/Core.cs +++ b/ArchiSteamFarm/Plugins/Core.cs @@ -31,6 +31,7 @@ using System.Reflection; using System.Threading.Tasks; using ArchiSteamFarm.Json; using ArchiSteamFarm.Localization; +using JetBrains.Annotations; using Newtonsoft.Json.Linq; using SteamKit2; @@ -63,6 +64,7 @@ namespace ArchiSteamFarm.Plugins { return true; } + [ItemNotNull] internal static async Task GetBotsComparer() { if ((ActivePlugins == null) || (ActivePlugins.Count == 0)) { return StringComparer.Ordinal; @@ -178,6 +180,7 @@ namespace ArchiSteamFarm.Plugins { } } + [ItemCanBeNull] internal static async Task OnBotCommand(Bot bot, ulong steamID, string message, string[] args) { if ((bot == null) || (steamID == 0) || string.IsNullOrEmpty(message) || (args == null) || (args.Length == 0)) { ASF.ArchiLogger.LogNullError(nameof(bot) + " || " + nameof(args)); @@ -292,6 +295,7 @@ namespace ArchiSteamFarm.Plugins { } } + [ItemCanBeNull] internal static async Task OnBotMessage(Bot bot, ulong steamID, string message) { if ((bot == null) || (steamID == 0) || string.IsNullOrEmpty(message)) { ASF.ArchiLogger.LogNullError(nameof(bot) + " || " + nameof(message)); diff --git a/ArchiSteamFarm/Plugins/IBotCommand.cs b/ArchiSteamFarm/Plugins/IBotCommand.cs index 5beb4b9ab..0d9cb5781 100644 --- a/ArchiSteamFarm/Plugins/IBotCommand.cs +++ b/ArchiSteamFarm/Plugins/IBotCommand.cs @@ -33,7 +33,8 @@ namespace ArchiSteamFarm.Plugins { /// Command message in its raw format, stripped of . /// Pre-parsed message using standard ASF delimiters. /// Response to the command, or null/empty (as the task value) if the command isn't handled by this plugin. + [ItemCanBeNull] [NotNull] - Task OnBotCommand([NotNull] Bot bot, ulong steamID, [NotNull] string message, [NotNull] string[] args); + Task OnBotCommand([NotNull] Bot bot, ulong steamID, [NotNull] string message, [ItemNotNull] [NotNull] string[] args); } } diff --git a/ArchiSteamFarm/Plugins/IBotMessage.cs b/ArchiSteamFarm/Plugins/IBotMessage.cs index 568b6a5ac..562bd7754 100644 --- a/ArchiSteamFarm/Plugins/IBotMessage.cs +++ b/ArchiSteamFarm/Plugins/IBotMessage.cs @@ -32,6 +32,7 @@ namespace ArchiSteamFarm.Plugins { /// 64-bit long unsigned integer of steamID executing the command. /// Message in its raw format. /// Response to the message, or null/empty (as the task value) for silence. + [ItemCanBeNull] [NotNull] Task OnBotMessage([NotNull] Bot bot, ulong steamID, [NotNull] string message); } diff --git a/ArchiSteamFarm/RuntimeCompatibility.cs b/ArchiSteamFarm/RuntimeCompatibility.cs index 91fe4a78e..753d0802f 100644 --- a/ArchiSteamFarm/RuntimeCompatibility.cs +++ b/ArchiSteamFarm/RuntimeCompatibility.cs @@ -22,9 +22,9 @@ using System; using System.Diagnostics; using System.Threading.Tasks; +using JetBrains.Annotations; #if NETFRAMEWORK -using JetBrains.Annotations; using System.Collections.Generic; using System.Net.WebSockets; using System.Threading; @@ -54,28 +54,30 @@ namespace ArchiSteamFarm { #pragma warning disable 1998 internal static class File { - internal static async Task AppendAllTextAsync(string path, string contents) => + internal static async Task AppendAllTextAsync([NotNull] string path, string contents) => #if NETFRAMEWORK System.IO.File.AppendAllText(path, contents); #else await System.IO.File.AppendAllTextAsync(path, contents).ConfigureAwait(false); #endif - internal static async Task ReadAllBytesAsync(string path) => + [ItemNotNull] + internal static async Task ReadAllBytesAsync([NotNull] string path) => #if NETFRAMEWORK System.IO.File.ReadAllBytes(path); #else await System.IO.File.ReadAllBytesAsync(path).ConfigureAwait(false); #endif - internal static async Task ReadAllTextAsync(string path) => + [ItemNotNull] + internal static async Task ReadAllTextAsync([NotNull] string path) => #if NETFRAMEWORK System.IO.File.ReadAllText(path); #else await System.IO.File.ReadAllTextAsync(path).ConfigureAwait(false); #endif - internal static async Task WriteAllTextAsync(string path, string contents) => + internal static async Task WriteAllTextAsync([NotNull] string path, string contents) => #if NETFRAMEWORK System.IO.File.WriteAllText(path, contents); #else @@ -94,7 +96,8 @@ namespace ArchiSteamFarm { } internal static class Path { - internal static string GetRelativePath(string relativeTo, string path) { + [NotNull] + internal static string GetRelativePath([NotNull] string relativeTo, [NotNull] string path) { #if NETFRAMEWORK if (!path.StartsWith(relativeTo, StringComparison.Ordinal)) { throw new NotImplementedException(); @@ -112,9 +115,11 @@ namespace ArchiSteamFarm { } #if NETFRAMEWORK - internal static async Task ReceiveAsync(this WebSocket webSocket, byte[] buffer, CancellationToken cancellationToken) => await webSocket.ReceiveAsync(new ArraySegment(buffer), cancellationToken).ConfigureAwait(false); - internal static async Task SendAsync(this WebSocket webSocket, byte[] buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) => await webSocket.SendAsync(new ArraySegment(buffer), messageType, endOfMessage, cancellationToken).ConfigureAwait(false); - internal static string[] Split(this string text, char separator, StringSplitOptions options = StringSplitOptions.None) => text.Split(new[] { separator }, options); + internal static async Task ReceiveAsync([NotNull] this WebSocket webSocket, [NotNull] byte[] buffer, CancellationToken cancellationToken) => await webSocket.ReceiveAsync(new ArraySegment(buffer), cancellationToken).ConfigureAwait(false); + internal static async Task SendAsync([NotNull] this WebSocket webSocket, [NotNull] byte[] buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) => await webSocket.SendAsync(new ArraySegment(buffer), messageType, endOfMessage, cancellationToken).ConfigureAwait(false); + + [NotNull] + internal static string[] Split([NotNull] this string text, char separator, StringSplitOptions options = StringSplitOptions.None) => text.Split(new[] { separator }, options); [PublicAPI] internal static void TrimExcess(this Dictionary _) { } // no-op diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index facd8a484..69566e397 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -23,6 +23,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; +using JetBrains.Annotations; namespace ArchiSteamFarm { internal static class SharedInfo { @@ -56,7 +57,10 @@ namespace ArchiSteamFarm { internal static string HomeDirectory => Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); internal static Guid ModuleVersion => Assembly.GetEntryAssembly().ManifestModule.ModuleVersionId; + + [NotNull] internal static string PublicIdentifier => AssemblyName + (BuildInfo.IsCustomBuild ? "-custom" : ""); + internal static Version Version => Assembly.GetEntryAssembly().GetName().Version; [SuppressMessage("ReSharper", "ConvertToConstant.Global")] diff --git a/ArchiSteamFarm/Statistics.cs b/ArchiSteamFarm/Statistics.cs index 2d895f291..dbe203dfb 100644 --- a/ArchiSteamFarm/Statistics.cs +++ b/ArchiSteamFarm/Statistics.cs @@ -28,6 +28,7 @@ using System.Threading; using System.Threading.Tasks; using ArchiSteamFarm.Json; using ArchiSteamFarm.Localization; +using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm { @@ -58,7 +59,7 @@ namespace ArchiSteamFarm { private DateTime LastPersonaStateRequest; private bool ShouldSendHeartBeats; - internal Statistics(Bot bot) { + internal Statistics([NotNull] Bot bot) { Bot = bot ?? throw new ArgumentNullException(nameof(bot)); MatchActivelyTimer = new Timer( @@ -182,6 +183,7 @@ namespace ArchiSteamFarm { } } + [ItemCanBeNull] private async Task> GetListedUsers() { const string request = URL + "/Api/Bots"; diff --git a/ArchiSteamFarm/SteamKit2/InMemoryServerListProvider.cs b/ArchiSteamFarm/SteamKit2/InMemoryServerListProvider.cs index 40a9d5c0c..5bf697f1b 100644 --- a/ArchiSteamFarm/SteamKit2/InMemoryServerListProvider.cs +++ b/ArchiSteamFarm/SteamKit2/InMemoryServerListProvider.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ArchiSteamFarm.Collections; +using JetBrains.Annotations; using Newtonsoft.Json; using SteamKit2.Discovery; @@ -32,8 +33,10 @@ namespace ArchiSteamFarm.SteamKit2 { [JsonProperty(Required = Required.DisallowNull)] private readonly ConcurrentHashSet ServerRecords = new ConcurrentHashSet(); + [NotNull] public Task> FetchServerListAsync() => Task.FromResult(ServerRecords.Select(server => ServerRecord.CreateServer(server.Host, server.Port, server.ProtocolTypes))); + [NotNull] public Task UpdateServerListAsync(IEnumerable endpoints) { if (endpoints == null) { ASF.ArchiLogger.LogNullError(nameof(endpoints)); diff --git a/ArchiSteamFarm/SteamKit2/ServerRecordEndPoint.cs b/ArchiSteamFarm/SteamKit2/ServerRecordEndPoint.cs index c21491363..161477b0a 100644 --- a/ArchiSteamFarm/SteamKit2/ServerRecordEndPoint.cs +++ b/ArchiSteamFarm/SteamKit2/ServerRecordEndPoint.cs @@ -20,6 +20,7 @@ // limitations under the License. using System; +using JetBrains.Annotations; using Newtonsoft.Json; using SteamKit2; @@ -34,7 +35,7 @@ namespace ArchiSteamFarm.SteamKit2 { [JsonProperty(Required = Required.Always)] internal readonly ProtocolTypes ProtocolTypes; - internal ServerRecordEndPoint(string host, ushort port, ProtocolTypes protocolTypes) { + internal ServerRecordEndPoint([NotNull] string host, ushort port, ProtocolTypes protocolTypes) { if (string.IsNullOrEmpty(host) || (port == 0) || (protocolTypes == 0)) { throw new ArgumentNullException(nameof(host) + " || " + nameof(port) + " || " + nameof(protocolTypes)); } diff --git a/ArchiSteamFarm/SteamSaleEvent.cs b/ArchiSteamFarm/SteamSaleEvent.cs index 80a029b14..e4891edff 100644 --- a/ArchiSteamFarm/SteamSaleEvent.cs +++ b/ArchiSteamFarm/SteamSaleEvent.cs @@ -25,6 +25,7 @@ using System.Threading; using System.Threading.Tasks; using ArchiSteamFarm.Localization; using HtmlAgilityPack; +using JetBrains.Annotations; namespace ArchiSteamFarm { internal sealed class SteamSaleEvent : IDisposable { @@ -33,7 +34,7 @@ namespace ArchiSteamFarm { private readonly Bot Bot; private readonly Timer SaleEventTimer; - internal SteamSaleEvent(Bot bot) { + internal SteamSaleEvent([NotNull] Bot bot) { Bot = bot ?? throw new ArgumentNullException(nameof(bot)); SaleEventTimer = new Timer( diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index 89a4d8884..6897211e2 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -41,7 +41,7 @@ namespace ArchiSteamFarm { private bool ParsingScheduled; - internal Trading(Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); + internal Trading([NotNull] Bot bot) => Bot = bot ?? throw new ArgumentNullException(nameof(bot)); public void Dispose() => TradesSemaphore.Dispose(); @@ -517,6 +517,7 @@ namespace ArchiSteamFarm { } } + [ItemCanBeNull] private async Task ShouldAcceptTrade(Steam.TradeOffer tradeOffer) { if (tradeOffer == null) { Bot.ArchiLogger.LogNullError(nameof(tradeOffer)); diff --git a/ArchiSteamFarm/Utilities.cs b/ArchiSteamFarm/Utilities.cs index 5a1c6cee6..dbcff4e72 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -30,6 +30,7 @@ using System.Threading; using System.Threading.Tasks; using Humanizer; using Humanizer.Localisation; +using JetBrains.Annotations; namespace ArchiSteamFarm { internal static class Utilities { @@ -237,6 +238,7 @@ namespace ArchiSteamFarm { } } + [NotNull] internal static string ReadLineMasked(char mask = '*') { StringBuilder result = new StringBuilder(); diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index b9901c2d5..60db6fa6a 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -48,7 +48,7 @@ namespace ArchiSteamFarm { private readonly HttpClient HttpClient; private readonly HttpClientHandler HttpClientHandler; - internal WebBrowser(ArchiLogger archiLogger, IWebProxy webProxy = null, bool extendedTimeout = false) { + internal WebBrowser([NotNull] ArchiLogger archiLogger, IWebProxy webProxy = null, bool extendedTimeout = false) { ArchiLogger = archiLogger ?? throw new ArgumentNullException(nameof(archiLogger)); HttpClientHandler = new HttpClientHandler { @@ -74,6 +74,7 @@ namespace ArchiSteamFarm { HttpClientHandler.Dispose(); } + [ItemCanBeNull] [PublicAPI] public async Task UrlGetToHtmlDocument(string request, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { @@ -87,6 +88,7 @@ namespace ArchiSteamFarm { return response != null ? new HtmlDocumentResponse(response) : null; } + [ItemCanBeNull] [PublicAPI] public async Task> UrlGetToJsonObject(string request, string referer = null, byte maxTries = MaxTries) where T : class { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { @@ -127,6 +129,7 @@ namespace ArchiSteamFarm { return null; } + [ItemCanBeNull] [PublicAPI] public async Task UrlGetToXmlDocument(string request, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { @@ -163,6 +166,7 @@ namespace ArchiSteamFarm { return null; } + [ItemCanBeNull] [PublicAPI] public async Task UrlHead(string request, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { @@ -189,6 +193,7 @@ namespace ArchiSteamFarm { return null; } + [ItemCanBeNull] [PublicAPI] public async Task UrlPost(string request, IReadOnlyCollection> data = null, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { @@ -215,6 +220,7 @@ namespace ArchiSteamFarm { return null; } + [ItemCanBeNull] [PublicAPI] public async Task UrlPostToHtmlDocument(string request, IReadOnlyCollection> data = null, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { @@ -228,6 +234,7 @@ namespace ArchiSteamFarm { return response != null ? new HtmlDocumentResponse(response) : null; } + [ItemCanBeNull] [PublicAPI] public async Task> UrlPostToJsonObject(string request, IReadOnlyCollection> data = null, string referer = null, byte maxTries = MaxTries) where T : class { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { @@ -268,6 +275,7 @@ namespace ArchiSteamFarm { return null; } + [NotNull] internal HttpClient GenerateDisposableHttpClient(bool extendedTimeout = false) { HttpClient result = new HttpClient(HttpClientHandler) { Timeout = TimeSpan.FromSeconds(extendedTimeout ? ExtendedTimeoutMultiplier * Program.GlobalConfig.ConnectionTimeout : Program.GlobalConfig.ConnectionTimeout) @@ -309,6 +317,7 @@ namespace ArchiSteamFarm { return htmlDocument; } + [ItemCanBeNull] internal async Task UrlGetToBinaryWithProgress(string request, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries)); @@ -380,6 +389,7 @@ namespace ArchiSteamFarm { return null; } + [ItemCanBeNull] internal async Task UrlGetToString(string request, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries)); @@ -546,6 +556,7 @@ namespace ArchiSteamFarm { } } + [ItemCanBeNull] private async Task UrlPostToString(string request, IReadOnlyCollection> data = null, string referer = null, byte maxTries = MaxTries) { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries)); @@ -574,7 +585,7 @@ namespace ArchiSteamFarm { public class BasicResponse { internal readonly Uri FinalUri; - internal BasicResponse(HttpResponseMessage httpResponseMessage) { + internal BasicResponse([NotNull] HttpResponseMessage httpResponseMessage) { if (httpResponseMessage == null) { throw new ArgumentNullException(nameof(httpResponseMessage)); } @@ -582,7 +593,7 @@ namespace ArchiSteamFarm { FinalUri = httpResponseMessage.Headers.Location ?? httpResponseMessage.RequestMessage.RequestUri; } - internal BasicResponse(BasicResponse basicResponse) { + internal BasicResponse([NotNull] BasicResponse basicResponse) { if (basicResponse == null) { throw new ArgumentNullException(nameof(basicResponse)); } @@ -595,7 +606,7 @@ namespace ArchiSteamFarm { [PublicAPI] public readonly HtmlDocument Content; - internal HtmlDocumentResponse(StringResponse stringResponse) : base(stringResponse) { + internal HtmlDocumentResponse([NotNull] StringResponse stringResponse) : base(stringResponse) { if (stringResponse == null) { throw new ArgumentNullException(nameof(stringResponse)); } @@ -608,7 +619,7 @@ namespace ArchiSteamFarm { [PublicAPI] public readonly T Content; - internal ObjectResponse(StringResponse stringResponse, T content) : base(stringResponse) { + internal ObjectResponse([NotNull] StringResponse stringResponse, T content) : base(stringResponse) { if (stringResponse == null) { throw new ArgumentNullException(nameof(stringResponse)); } @@ -621,7 +632,7 @@ namespace ArchiSteamFarm { [PublicAPI] public readonly XmlDocument Content; - internal XmlDocumentResponse(StringResponse stringResponse, XmlDocument content) : base(stringResponse) { + internal XmlDocumentResponse([NotNull] StringResponse stringResponse, XmlDocument content) : base(stringResponse) { if (stringResponse == null) { throw new ArgumentNullException(nameof(stringResponse)); } @@ -633,7 +644,7 @@ namespace ArchiSteamFarm { internal sealed class BinaryResponse : BasicResponse { internal readonly byte[] Content; - internal BinaryResponse(HttpResponseMessage httpResponseMessage, byte[] content) : base(httpResponseMessage) { + internal BinaryResponse([NotNull] HttpResponseMessage httpResponseMessage, [NotNull] byte[] content) : base(httpResponseMessage) { if ((httpResponseMessage == null) || (content == null)) { throw new ArgumentNullException(nameof(httpResponseMessage) + " || " + nameof(content)); } @@ -645,7 +656,7 @@ namespace ArchiSteamFarm { internal sealed class StringResponse : BasicResponse { internal readonly string Content; - internal StringResponse(HttpResponseMessage httpResponseMessage, string content) : base(httpResponseMessage) { + internal StringResponse([NotNull] HttpResponseMessage httpResponseMessage, [NotNull] string content) : base(httpResponseMessage) { if ((httpResponseMessage == null) || (content == null)) { throw new ArgumentNullException(nameof(httpResponseMessage) + " || " + nameof(content)); }