/// <summary> /// Reads how many days of escrow the user has /// </summary> /// <param name="trade">Trade object containing user information</param> /// <returns>Returns EscrowDuration class, if failed returns null</returns> public int GetUserEscrowWaitingPeriod(Config.TradeObject trade) { string url = "https://steamcommunity.com/tradeoffer/new/"; SteamID steamId = new SteamID(); steamId.SetFromUInt64(trade.SteamId); var data = new NameValueCollection(); data.Add("partner", steamId.AccountID.ToString()); data.Add("token", trade.RU_Token); string response = string.Empty; for (int i = 0; i < 3; i++) { try { response = mSteam.Web.Fetch(url, "GET", data, false); } catch (WebException ex) { var webResponse = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd(); mLogOffer.Write(Log.LogLevel.Error, $"Web exception when getting user escrow waiting period at {ex.Message}"); } } return(Functions.ParseEscrowResponse(response)); }
/// <summary> /// Request items from a deposit /// </summary> /// <param name="steamid">User steamid64</param> /// <param name="tradeToken">User trade token</param> /// <param name="message">Message to include in offer</param> /// <param name="itemList">List of item ids</param> /// <returns>Returns empty string if failed, else offerid</returns> public string SendTradeOffer(Config.TradeObject trade, string message) { var offer = mSteam.TradeOfferManager.NewOffer(trade.SteamId); mLogOffer.Write(Log.LogLevel.Debug, $"Created new trade offer to user {trade.SteamId} to {trade.tradeType} with security token {trade.SecurityToken}."); var addedItems = new List <long>(); foreach (var item in trade.Items) { if (item.AssetId == 0) { mLog.Write(Log.LogLevel.Debug, $"AssetId for this item was 0. Skipping."); break; } addedItems.Add(item.AssetId); switch (trade.tradeType) { /*For deposit we want to add their items*/ case Config.TradeType.Deposit: offer.Items.AddTheirItem(730, 2, item.AssetId); mLogOffer.Write(Log.LogLevel.Debug, $"Added their item to trade. ClassID/AssetId: {item.ClassId}/{item.AssetId}"); break; /*As for withdraw we want to add our items*/ case Config.TradeType.Withdraw: offer.Items.AddMyItem(730, 2, item.AssetId); mLogOffer.Write(Log.LogLevel.Debug, $"Added my item to trade. ClassID/AssetId: {item.ClassId}/{item.AssetId}"); break; } } if (addedItems.Count == 0) { mLog.Write(Log.LogLevel.Warn, $"No items to add to trade"); return(string.Empty); } return(RequestTradeOffer(offer, trade, message)); }
/// <summary> /// Checks if a user has an escrow waiting period /// </summary> /// <param name="trade">Trade to check</param> /// <returns>Returns true if it's ok to trade</returns> private bool IsUserEscrowReady(Config.TradeObject trade) { int daysTheirEscrow = mBotHost.GetUserEscrowWaitingPeriod(trade); if (daysTheirEscrow > 0) { /*User has an escrow waiting period, which means we can't sent the trade to them*/ mLog.Write(Log.LogLevel.Error, $"User {trade.SteamId} has an escrow waiting period of {daysTheirEscrow} days. Will not continue."); trade.tradeStatus.Status = trade.tradeType == Config.TradeType.Deposit ? Config.TradeStatusType.DepositDeclined : Config.TradeStatusType.WithdrawDeclined; /*123 is the default number that means something went wrong with the request*/ if (daysTheirEscrow == 123) { mLog.Write(Log.LogLevel.Info, $"123 days means that it failed to check how many days the user has left."); } return(false); } return(true); }
/// <summary> /// Sends trade offer to user /// </summary> /// <param name="offer">Offer to send</param> /// <returns>Returns empty if failed, else offer id</returns> private string RequestTradeOffer(TradeOffer offer, Config.TradeObject trade, string message) { string offerId = string.Empty; string exceptionMsg = string.Empty; for (int i = 0; i < 5; i++) { try { if (offer.SendWithToken(out offerId, trade.RU_Token, message)) { mLogOffer.Write(Log.LogLevel.Debug, $"Trade offer sent to user {offer.PartnerSteamId} with id {offerId}"); break; } } catch (WebException ex) { var respStream = ex?.Response?.GetResponseStream(); if (respStream != null) { var read = new StreamReader(respStream).ReadToEnd(); exceptionMsg = $"Webexeption: {read}"; } } catch (Exception ex) { exceptionMsg = $"Exception: {ex.Message}"; } mLogOffer.Write(Log.LogLevel.Warn, $"Unable to send trade offer to user {trade.SteamId}. Trying again in 3 seconds."); Thread.Sleep(3000); } if (string.IsNullOrWhiteSpace(offerId)) { mLogOffer.Write(Log.LogLevel.Error, $"Failed to send trade offer to user {trade.SteamId}. Error: {exceptionMsg}"); } return(offerId); }
/// <summary> /// Updates the bot owner of items /// </summary> /// <param name="trade">tradeobject</param> /// <param name="ownerId">owner to update to</param> public void UpdateItemOwners(Config.TradeObject trade) { using (var transaction = mSqlCon.BeginTransaction()) { foreach (var item in trade.Items) { using (var cmd = new SQLiteCommand($"UPDATE items SET BotOwner = {trade.SteamId} WHERE ID = {item.ID}", mSqlCon)) { cmd.ExecuteNonQuery(); } } try { transaction.Commit(); } catch (Exception ex) { mLog.Write(Log.LogLevel.Info, $"Error updating items ex: {ex.Message}"); } } }
/// <summary> /// Deal with deposit offers /// </summary> /// <param name="trade">TradeObject</param> private Config.TradeStatus HandleDeposit(Config.TradeObject trade) { /*Attempt to send the trade offer to user*/ mLog.Write(Log.LogLevel.Info, $"Attempting to send deposit trade offer to {trade.SteamId} with token {trade.SecurityToken}"); string offerId = mBotHost.SendTradeOffer(trade, $"{EndPoints.Website.DOMAIN.ToUpper()} DEPOSIT | {trade.SecurityToken}"); if (string.IsNullOrWhiteSpace(offerId)) { /*Trade offer id was empty, so that means the offer failed to send*/ mLog.Write(Log.LogLevel.Error, $"Deposit trade offer was not sent to user {trade.SteamId}"); trade.tradeStatus.Status = Config.TradeStatusType.DepositDeclined; } else { /*Offer was sent successfully*/ mLog.Write(Log.LogLevel.Success, $"Deposit trade offer was sent to user {trade.SteamId}"); trade.tradeStatus.Status = Config.TradeStatusType.DepositSent; trade.tradeStatus.Tradelink = offerId; mActiveTradesListQueue.Add(trade); } return(trade.tradeStatus); }
/// <summary> /// Deal with withdraw offers /// </summary> /// <param name="trade">TradeObject</param> private Config.TradeStatus HandleWithdraw(Config.TradeObject trade) { /*Get all items from database*/ var itemList = new List <Config.Item>(); foreach (var item in trade.Items.GroupBy(o => o.ClassId).Select(q => q.First())) { itemList.AddRange(mDatabase.FindEntries(Database.DBCols.ClassId, item.ClassId.ToString())); } /*Sort them so we'll best the best possible bots*/ itemList = Functions.SortDBItems(itemList, trade.Items); mLog.Write(Log.LogLevel.Info, $"Found {itemList.Count} perfect items. Requested count: {trade.Items.Count}"); /*We won't really do anything about this, but it's good to keep track of*/ if (itemList.Count < trade.Items.Count) { mLog.Write(Log.LogLevel.Error, $"We found less items than what was requested"); } /*Group up all the items depending on the owner*/ var itemGroups = itemList.GroupBy(o => o.BotOwner); /*Go through all the groups*/ int offersSent = 0; foreach (var group in itemGroups) { /*Find the bot that owns this item based on steamid*/ var bot = mBotList.Find(o => o.GetBotSteamId64() == group.Key); /*Make sure we don't want to send a trade from hostbot to hostbot * because obviously that won't work, dummy. And there's no need to*/ if (bot.GetBotSteamId64() == mBotHost.GetBotSteamId64()) { continue; } /*Set up a trade object*/ var storageTrade = new Config.TradeObject() { Items = FindUpdatedItems(bot.GetInventory(), group.ToList()), RU_Token = mBotHost.mSettings.tradeToken, SteamId = mBotHost.GetBotSteamId64(), tradeType = Config.TradeType.Withdraw, tradeStatus = new Config.TradeStatus() }; /*Send the trade offer*/ var storeOfferId = bot.SendTradeOffer(storageTrade, EndPoints.Steam.STORAGE_MESSAGE); if (string.IsNullOrWhiteSpace(storeOfferId)) { mLog.Write(Log.LogLevel.Error, $"Inhouse offer wasn't sent"); } else { offersSent++; mLog.Write(Log.LogLevel.Success, $"Inhouse trade offer sent"); mDatabase.InsertUsedItems(storageTrade.Items.Select(o => o.AssetId).ToList()); storageTrade.tradeStatus.Id = storeOfferId; Thread.Sleep(1000); bot.ConfirmTrades(); } } /*Accept all trades on hostbot*/ if (offersSent > 0) { Thread.Sleep(3000); mBotHost.GetOffers(); } /*Get the new itemids for each item*/ var newItemList = FindUpdatedItems(mBotHost.GetInventory(), itemList); if (newItemList.Count < itemList.Count) { mLog.Write(Log.LogLevel.Info, $"We're missing items to withdraw."); trade.tradeStatus.Status = Config.TradeStatusType.WithdrawDeclined; return(trade.tradeStatus); } else { /*Set the updated list to trade list*/ trade.Items = newItemList; } /*Send the trade offer*/ mLog.Write(Log.LogLevel.Info, $"Attempting to send withdraw trade offer to {trade.SteamId} with token {trade.SecurityToken}"); string offerId = mBotHost.SendTradeOffer(trade, $"{EndPoints.Website.DOMAIN.ToUpper()} WITHDRAW | {trade.SecurityToken}"); if (string.IsNullOrWhiteSpace(offerId)) { /*Trade offer id was empty, so that means the offer failed to send*/ mLog.Write(Log.LogLevel.Error, $"Withdraw trade offer was not sent to user {trade.SteamId}"); trade.tradeStatus.Status = Config.TradeStatusType.WithdrawDeclined; } else { /*Offer was sent successfully, update the trade status*/ mLog.Write(Log.LogLevel.Success, $"Withdraw trade offer was sent to user {trade.SteamId}"); trade.tradeStatus.Status = Config.TradeStatusType.WithdrawSent; trade.tradeStatus.Tradelink = offerId; /*Set state to sent which means that next withdraw won't pick the same items*/ var idList = trade.Items.Select(o => o.ID).ToList(); mDatabase.UpdateItemStates(idList, Database.ItemState.Sent); mDatabase.InsertUsedItems(trade.Items.Select(o => o.AssetId).ToList()); mLog.Write(Log.LogLevel.Info, $"{idList.Count} items updated in the database"); mActiveTradesListQueue.Add(trade); } return(trade.tradeStatus); }
/// <summary> /// Sends items to storage bots /// </summary> private void SendItemsToStorage() { /*Check how many items in the database that belongs to the host bot*/ var hostItemList = mDatabase.FindEntries(Database.DBCols.BotOwner, mBotHost.GetBotSteamId64().ToString()); mLog.Write(Log.LogLevel.Debug, $"Host owns {hostItemList.Count} items that can be sent to storage"); if (hostItemList.Count >= mSettings.hostItemLimit) { mLog.Write(Log.LogLevel.Info, $"We have {hostItemList.Count} items stored on Host. Moving some to storage."); /*Set all selected items to busy so they won't be touched*/ mDatabase.UpdateItemStates(hostItemList.Select(o => o.ID).ToList(), Database.ItemState.Busy); /*Go through all storage bots*/ foreach (var bot in mBotList.Where(o => o.mBotType == Bot.BotType.Storage)) { /*Load the inventory and skip if we have too many items*/ var inventory = bot.GetInventory(true); if (inventory.Count() >= mSettings.itemLimitPerBot) { continue; } /*Get amount of free slots on the bot * Although we need to limit it by n to ensure a stable offer*/ int inventorySlots = mSettings.itemLimitPerBot - inventory.Count(); if (inventorySlots > mSettings.storageTradeOfferMaxItems) { inventorySlots = mSettings.storageTradeOfferMaxItems; } /*Take items from the original list * We also need to make sure we have more than one item to trade*/ var itemList = hostItemList.Take(inventorySlots).ToList(); if (itemList.Count() > 0) { /*Set up a trade object to the storage bot*/ var trade = new Config.TradeObject() { Items = FindUpdatedItems(mBotHost.GetInventory(), itemList), RU_Token = bot.mSettings.tradeToken, SteamId = bot.GetBotSteamId64(), tradeType = Config.TradeType.Withdraw, tradeStatus = new Config.TradeStatus() }; /*Send trade offer from host bot to this bot*/ var offerId = mBotHost.SendTradeOffer(trade, EndPoints.Steam.STORAGE_MESSAGE); if (string.IsNullOrWhiteSpace(offerId)) { mLog.Write(Log.LogLevel.Error, $"Storage offer failed to send? Beep boop error pls fix"); /*Since the offer failed we set all the items back to active*/ mDatabase.UpdateItemStates(hostItemList.Select(o => o.ID).ToList(), Database.ItemState.Active); } else { mLog.Write(Log.LogLevel.Success, $"Storage offer sent to bot {bot.mSettings.username}"); trade.tradeStatus.Tradelink = offerId; /*Add items sent to used items in the database*/ mDatabase.InsertUsedItems(trade.Items.Select(o => o.AssetId).ToList()); /*Set item state to storage sent*/ var idList = trade.Items.Select(o => o.ID).ToList(); mDatabase.UpdateItemStates(idList, Database.ItemState.OnHold); mLog.Write(Log.LogLevel.Info, $"{idList.Count} items updated in the database to OnHold"); mActiveStorageTradesList.Add(trade); } } /*Since we got this far then we can stop checking*/ break; } Thread.Sleep(1500); } }