Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 68 additions & 15 deletions src/Classes/TradeQuery.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ local TradeQueryClass = newClass("TradeQuery", function(self, itemsTab)
self.resultTbl = { }
self.sortedResultTbl = { }
self.itemIndexTbl = { }
self.queryIdTbl = { }
-- tooltip acceleration tables
self.onlyWeightedBaseOutput = { }
self.lastComparedWeightList = { }
Expand Down Expand Up @@ -359,6 +360,20 @@ Highest Weight - Displays the order retrieved from trade]]
-- self:PullPoENinjaCurrencyConversion(self.pbLeague)
end)
self.controls.pbNotice = new("LabelControl", {"BOTTOMRIGHT", nil, "BOTTOMRIGHT"}, {-row_height - pane_margins_vertical - row_vertical_padding, -pane_margins_vertical - row_height - row_vertical_padding, 300, row_height}, "")

-- Add Trade Mode dropdown to the bottom right
self.tradeModeList = {
"Instant Buyout and In Person Trade",
"Instant Buyout Only",
"In Person Trade Only",
"Any"
}
self.pbTradeModeSelectionIndex = self.pbTradeModeSelectionIndex or 3
self.controls.tradeModeSelection = new("DropDownControl", {"BOTTOMRIGHT", nil, "BOTTOMRIGHT"}, {-pane_margins_horizontal, -pane_margins_vertical, 220, row_height}, self.tradeModeList, function(index, value)
self.pbTradeModeSelectionIndex = index
end)
self.controls.tradeModeSelection:SetSel(self.pbTradeModeSelectionIndex)
self.controls.tradeModeSelection.enableDroppedWidth = true

-- Realm selection
self.controls.realmLabel = new("LabelControl", {"LEFT", self.controls.setSelect, "RIGHT"}, {18, 0, 20, row_height - 4}, "^7Realm:")
Expand Down Expand Up @@ -486,6 +501,7 @@ Highest Weight - Displays the order retrieved from trade]]
end
end
end

self.controls.fullPrice = new("LabelControl", {"BOTTOM", nil, "BOTTOM"}, {0, -row_height - pane_margins_vertical - row_vertical_padding, pane_width - 2 * pane_margins_horizontal, row_height}, "")
self.controls.close = new("ButtonControl", {"BOTTOM", nil, "BOTTOM"}, {0, -pane_margins_vertical, 90, row_height}, "Done", function()
main:ClosePopup()
Expand Down Expand Up @@ -844,7 +860,7 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
local nameColor = slotTbl.unique and colorCodes.UNIQUE or "^7"
controls["name"..row_idx] = new("LabelControl", top_pane_alignment_ref, {0, row_idx*(row_height + row_vertical_padding), 100, row_height - 4}, nameColor..slotTbl.slotName)
controls["bestButton"..row_idx] = new("ButtonControl", { "LEFT", controls["name"..row_idx], "LEFT"}, {100 + 8, 0, 80, row_height}, "Find best", function()
self.tradeQueryGenerator:RequestQuery(activeSlot, { slotTbl = slotTbl, controls = controls, row_idx = row_idx }, self.statSortSelectionList, function(context, query, errMsg)
self.tradeQueryGenerator:RequestQuery(activeSlot, { slotTbl = slotTbl, controls = controls, row_idx = row_idx }, self.statSortSelectionList, self.pbTradeModeSelectionIndex, function(context, query, errMsg)
if errMsg then
self:SetNotice(context.controls.pbNotice, colorCodes.NEGATIVE .. errMsg)
return
Expand Down Expand Up @@ -873,6 +889,7 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
end,
{
callbackQueryId = function(queryId)
self.queryIdTbl[context.row_idx] = queryId
local url = self.tradeQueryRequests:buildUrl(self.hostName .. "trade2/search", self.pbRealm, self.pbLeague, queryId)
controls["uri"..context.row_idx]:SetText(url, true)
end
Expand Down Expand Up @@ -922,7 +939,12 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
self:UpdateControlsWithItems(row_idx)
end
controls["priceButton"..row_idx].label = "Price Item"
end)
end,
{
callbackQueryId = function(queryId)
self.queryIdTbl[row_idx] = queryId
end
})
end)
controls["priceButton"..row_idx].enabled = function()
local poesessidAvailable = main.POESESSID and main.POESESSID ~= ""
Expand Down Expand Up @@ -1001,22 +1023,53 @@ function TradeQueryClass:PriceItemRowDisplay(row_idx, top_pane_alignment_ref, ro
end
-- Whisper so we can copy to clipboard
controls["whisperButton"..row_idx] = new("ButtonControl", { "TOPLEFT", controls["importButton"..row_idx], "TOPRIGHT"}, {8, 0, 185, row_height}, function()
return self.totalPrice[row_idx] and "Whisper for " .. self.totalPrice[row_idx].amount .. " " .. self.totalPrice[row_idx].currency or "Whisper"
if not self.itemIndexTbl[row_idx] then return "Whisper" end
local result = self.resultTbl[row_idx][self.itemIndexTbl[row_idx]]
local priceStr = self.totalPrice[row_idx] and " for " .. self.totalPrice[row_idx].amount .. " " .. self.totalPrice[row_idx].currency or ""
if result.hideout_token then
return "Teleport" .. priceStr
elseif result.whisper_token then
return "Whisper" .. priceStr
else
return "Copy Whisper" .. priceStr
end
end, function()
Copy(self.resultTbl[row_idx][self.itemIndexTbl[row_idx]].whisper)
end)
controls["whisperButton"..row_idx].enabled = function()
return self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]].whisper ~= nil
end
controls["whisperButton"..row_idx].tooltipFunc = function(tooltip)
tooltip:Clear()
if self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]].item_string then
tooltip.center = true
tooltip:AddLine(16, "Copies the item purchase whisper to the clipboard")
local result = self.resultTbl[row_idx][self.itemIndexTbl[row_idx]]
local token = result.hideout_token or result.whisper_token

if token then
local queryId = self.queryIdTbl and self.queryIdTbl[row_idx]
local referrerUrl = queryId and self.tradeQueryRequests:buildUrl(self.hostName .. "trade2/search", self.pbRealm, self.pbLeague, queryId)

if not referrerUrl then
ConPrintf("Error: Could not construct referrer URL for whisper.")
if result.whisper then Copy(result.whisper) end
return
end

self.tradeQueryRequests:SendWhisper(token, referrerUrl, function(response, errMsg)
local action = result.hideout_token and "Teleport" or "Whisper"
if errMsg or (response and response.error) then
local errorMsgStr = "Error: " .. (errMsg or (response.error and response.error.message) or "Unknown error")
ConPrintf("Action '%s' failed: %s", action, errorMsgStr)
self:SetNotice(self.controls.pbNotice, errorMsgStr)
if result.whisper then
ConPrintf("Falling back to clipboard copy.")
Copy(result.whisper)
end
else
ConPrintf("'%s' action successful!", action)
self:SetNotice(self.controls.pbNotice, action .. " sent!")
end
end)
elseif result.whisper then
ConPrintf("No token found. Falling back to clipboard copy.")
Copy(result.whisper)
else
ConPrintf("No token and no whisper text found. Cannot perform action.")
end
end
end)
end

-- Method to update the Total Price string sum of all items
function TradeQueryClass:GetTotalPriceString()
local text = ""
Expand Down
8 changes: 6 additions & 2 deletions src/Classes/TradeQueryGenerator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,9 @@ function TradeQueryGeneratorClass:FinishQuery()
-- This Stat diff value will generally be higher than the weighted sum of the same item, because the stats are all applied at once and can thus multiply off each other.
-- So apply a modifier to get a reasonable min and hopefully approximate that the query will start out with small upgrades.
local minWeight = megalomaniacSpecialMinWeight or currentStatDiff * 0.5
local tradeModeMap = { "available", "securable", "online", "any" }
local tradeMode = tradeModeMap[self.calcContext.options.tradeModeIndex] or "online"


-- Generate trade query str and open in browser
local filters = 0
Expand All @@ -829,7 +832,7 @@ function TradeQueryGeneratorClass:FinishQuery()
}
}
},
status = { option = "online" },
status = { option = tradeMode },
stats = {
{
type = "weight",
Expand Down Expand Up @@ -910,7 +913,7 @@ function TradeQueryGeneratorClass:FinishQuery()
main:ClosePopup()
end

function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callback)
function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, tradeModeIndex, callback)
self.requesterCallback = callback
self.requesterContext = context

Expand Down Expand Up @@ -1029,6 +1032,7 @@ function TradeQueryGeneratorClass:RequestQuery(slot, context, statWeights, callb
options.sockets = tonumber(controls.sockets.buf)
end
options.statWeights = statWeights
options.tradeModeIndex = tradeModeIndex

self:StartQuery(slot, options)
end)
Expand Down
4 changes: 3 additions & 1 deletion src/Classes/TradeQueryRateLimiter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ local TradeQueryRateLimiterClass = newClass("TradeQueryRateLimiter", function(se
-- convenient name lookup, can be extended
self.policyNames = {
["search"] = "trade-search-request-limit",
["fetch"] = "trade-fetch-request-limit"
["fetch"] = "trade-fetch-request-limit",
["whisper"] = "trade-whisper-request-limit"
}
self.delayCache = {}
self.requestId = 0
Expand All @@ -53,6 +54,7 @@ local TradeQueryRateLimiterClass = newClass("TradeQueryRateLimiter", function(se
self.pendingRequests = {
["trade-search-request-limit"] = {},
["trade-fetch-request-limit"] = {},
["trade-whisper-request-limit"] = {},
["character-list-request-limit-poe2"] = {},
["character-request-limit-poe2"] = {}
}
Expand Down
66 changes: 57 additions & 9 deletions src/Classes/TradeQueryRequests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ local TradeQueryRequestsClass = newClass("TradeQueryRequests", function(self, ra
self.requestQueue = {
["search"] = {},
["fetch"] = {},
["whisper"] = {},
}
self.hostName = "https://www.pathofexile.com/"
end)
Expand All @@ -30,31 +31,39 @@ function TradeQueryRequestsClass:ProcessQueue()
local requestId = self.rateLimiter:InsertRequest(policy)
local onComplete = function(response, errMsg)
self.rateLimiter:FinishRequest(policy, requestId)
self.rateLimiter:UpdateFromHeader(response.header)
if response.header:match("HTTP/[%d%.]+ (%d+)") == "429" then
if response and response.header then
self.rateLimiter:UpdateFromHeader(response.header)
end
if response and response.header and response.header:match("HTTP/[%d%.]+ (%d+)") == "429" then
table.insert(queue, 1, request)
return
end
-- if limit rules don't return account then the POESESSID is invalid.
if response.header:match("X%-Rate%-Limit%-Rules: (.-)\n"):match("Account") == nil and main.POESESSID ~= "" then
if response and response.header and response.header:match("X%-Rate%-Limit%-Rules: (.-)\n") and response.header:match("X%-Rate%-Limit%-Rules: (.-)\n"):match("Account") == nil and main.POESESSID ~= "" then
main.POESESSID = ""
if errMsg then
errMsg = errMsg .. "\nPOESESSID is invalid. Please Re-Log and reset"
else
errMsg = "POESESSID is invalid. Please Re-Log and reset"
end
end
request.callback(response.body, errMsg, unpack(request.callbackParams or {}))
request.callback(response and response.body or nil, errMsg, unpack(request.callbackParams or {}))
end
-- self:SendRequest(request.url , onComplete, {body = request.body, poesessid = main.POESESSID})
local header = "Content-Type: application/json"

local header = request.headers or "Content-Type: application/json\nUser-Agent: Path of Building Community"
if main.POESESSID ~= "" then
header = header .. "\nCookie: POESESSID=" .. main.POESESSID
end
launch:DownloadPage(request.url, onComplete, {

local downloadOptions = {
header = header,
body = request.body,
})
body = request.body
}
if request.body then
downloadOptions.post = "raw"
end

launch:DownloadPage(request.url, onComplete, downloadOptions)
else
break
end
Expand Down Expand Up @@ -414,6 +423,8 @@ function TradeQueryRequestsClass:FetchResultBlock(url, callback)
currency = trade_entry.listing.price.currency,
item_string = table.concat(rawLines, "\n"),
whisper = trade_entry.listing.whisper,
whisper_token = trade_entry.listing.whisper_token,
hideout_token = trade_entry.listing.hideout_token,
weight = trade_entry.item.pseudoMods and trade_entry.item.pseudoMods[1]:match("Sum: (.+)") or "0",
id = trade_entry.id
})
Expand Down Expand Up @@ -525,3 +536,40 @@ function TradeQueryRequestsClass:buildUrl(root, realm, league, queryId)
end
return result
end

---@param callback fun(items:table, errMsg:string)
function TradeQueryRequestsClass:SendWhisper(token, refererUrl, callback)
ConPrintf("Attempting to send whisper with token: " .. tostring(token))

-- Manually construct the JSON string to ensure a space after the colon
local requestBody = '{"token": "' .. token .. '"}'

-- Construct the full headers required by the whisper API
local headers = {
"Content-Type: application/json",
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36",
"X-Requested-With: XMLHttpRequest"
}
if refererUrl then
table.insert(headers, "Referer: " .. refererUrl)
end

table.insert(self.requestQueue["whisper"], {
url = self.hostName .. "api/trade2/whisper",
body = requestBody,
headers = table.concat(headers, "\n"),
callback = function(responseBody, errMsg)
ConPrintf("Whisper API Response Body: " .. tostring(responseBody))
ConPrintf("Whisper API Error Message: " .. tostring(errMsg))
if errMsg then
return callback(nil, errMsg)
end
local response, jsonErr = dkjson.decode(responseBody)
if not response then
errMsg = "Failed to decode Whisper JSON response: " .. (jsonErr or "Empty response")
return callback(nil, errMsg)
end
callback(response, errMsg)
end,
})
end