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
6 changes: 6 additions & 0 deletions src/Classes/PoEAPI.lua
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,9 @@ function PoEAPIClass:DownloadCharacter(realm, name, callback)
self:DownloadWithRateLimit("character-request-limit",
"/character" .. (realm == "pc" and "" or "/" .. realm) .. "/" .. name, callback)
end

---@param realm string Realm to fetch the leagues for
---@param callback DownloadCallback
function PoEAPIClass:FetchLeagues(realm, callback)
self:DownloadWithRateLimit("league-request-limit", "/account/leagues" .. ((realm == "pc") and "" or ("/" .. realm)), callback)
end
154 changes: 61 additions & 93 deletions src/Classes/TradeQuery.lua
Original file line number Diff line number Diff line change
Expand Up @@ -72,39 +72,6 @@ function TradeQueryClass:TradeQuery(itemsTab)
end



-- Method to pull down and interpret available leagues from PoE
function TradeQueryClass:PullLeagueList()
launch:DownloadPage(
self.hostName .. "api/leagues?type=main&compact=1",
function(response, errMsg)
if errMsg then
self:SetNotice(self.controls.pbNotice, "Error: " .. tostring(errMsg))
return "POE ERROR", "Error: "..errMsg
else
local json_data = dkjson.decode(response.body)
if not json_data then
self:SetNotice(self.controls.pbNotice, "Failed to Get PoE League List response")
return
end
table.sort(json_data, function(a, b)
if a.endAt == nil then return false end
if b.endAt == nil then return true end
return a.id < b.id
end)
self.itemsTab.leagueDropList = {}
for _, league_data in pairs(json_data) do
if not league_data.id:find("SSF") then
t_insert(self.itemsTab.leagueDropList,league_data.id)
end
end
self.controls.league:SetList(self.itemsTab.leagueDropList)
self.controls.league.selIndex = 1
self.pbLeague = self.itemsTab.leagueDropList[self.controls.league.selIndex]
end
end)
end

--- @param currencyId string
--- @param amount integer
--- @return number?
Expand Down Expand Up @@ -341,8 +308,10 @@ function TradeQueryClass:PriceItem()
main:SaveSettings()

TradeQueryClass:SetNotice(self.controls.pbNotice, "")
self:UpdateRealms()
else
self.loginStatus = colorCodes.WARNING.."Not authenticated"
self:UpdateRealms()
end
end)
self.clickTime = os.time()
Expand All @@ -355,11 +324,12 @@ function TradeQueryClass:PriceItem()
main.tokenExpiry = nil
main.api.tokenExpiry = nil
main:SaveSettings()
self:UpdateRealms()
end
end)
self.controls.tradeAuthButton.tooltipText = [[
The Trader feature supports two modes of operation depending on the authorization availability.
You can click this button to authorize PoB by logging in.
You can click this button to authorize PoB by logging in. The URL is also copied to your clipboard.

^2Session Mode^7
- Requires authorization on pathofexile.com.
Expand Down Expand Up @@ -469,9 +439,17 @@ Highest Weight - Displays the order retrieved from trade]]
local function setLeagueDropList()
self.itemsTab.leagueDropList = copyTable(self.allLeagues[self.pbRealm])
self.controls.league:SetList(self.itemsTab.leagueDropList)
-- correct index as it might move when we fetch a new league list
local leagueIndex = self.pbLeagueIndex
for index, league in ipairs(self.itemsTab.leagueDropList) do
if league == self.pbLeague then
leagueIndex = index
break
end
end
-- invalidate selIndex to trigger select function call in the SetSel
self.controls.league.selIndex = nil
self.controls.league:SetSel(self.pbLeagueIndex)
self.controls.league:SetSel(leagueIndex)
end
if self.allLeagues[self.pbRealm] then
setLeagueDropList()
Expand Down Expand Up @@ -1275,46 +1253,46 @@ you can add them, copy the link here, and press "Price Item" to evaluate the ite
end
-- Whisper so we can copy to clipboard
controls["whisperButton" .. row_idx] = new("ButtonControl"):ButtonControl({ "TOPLEFT", controls["importButton" .. row_idx], "TOPRIGHT" }, { 8, 0, 155, row_height }, function()
local itemResult = self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]]
local itemResult = self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]]

if not itemResult then return "" end
if not itemResult then return "" end

local price = self.totalPrice[row_idx] and
self.totalPrice[row_idx].amount .. " " .. self.totalPrice[row_idx].currency
local price = self.totalPrice[row_idx] and
self.totalPrice[row_idx].amount .. " " .. self.totalPrice[row_idx].currency

-- we also check the price type so we can prefer instant buyout over
-- whisper
if itemResult.whisper and (itemResult.priceType ~= "~b/o") then
return price and "Whisper for " .. price or "Whisper"
else
return price and "Search for " .. price or "Search"
end

end, function()
local itemResult = self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]]
if itemResult.whisper and (itemResult.priceType ~= "~b/o") then
Copy(itemResult.whisper)
else
local exactQuery = dkjson.decode(self.lastQueries[row_idx])
-- use trade sum to get the specific item. both min and max
-- weight on site uses floats but only shows integer in the api
-- e.g. weight of 172.3 shows up as 172 in the api
exactQuery.query.stats[1].value = { min = floor(itemResult.weight, 1) - 1, max = round(itemResult.weight, 1) + 1 }
-- also apply trader name. this should make false positives
-- extremely unlikely. this doesn't seem to take up a filter slot
exactQuery.query.filters = exactQuery.query.filters or { }
exactQuery.query.filters.trade_filters = exactQuery.query.filters.trade_filters or { filters = { } }
exactQuery.query.filters.trade_filters.filters = exactQuery.query.filters.trade_filters.filters or { }
exactQuery.query.filters.trade_filters.filters.account = { input = itemResult.trader }

local exactQueryStr = dkjson.encode(exactQuery)

local encodedUrl = s_format("https://www.pathofexile.com/trade/search/%s?q=%s", self.pbLeague, urlEncode(exactQueryStr))

Copy(encodedUrl)
OpenURL(encodedUrl)
end
end)
-- we also check the price type so we can prefer instant buyout over
-- whisper
if itemResult.whisper and (itemResult.priceType ~= "~b/o") then
return price and "Whisper for " .. price or "Whisper"
else
return price and "Search for " .. price or "Search"
end
end, function()
local itemResult = self.itemIndexTbl[row_idx] and self.resultTbl[row_idx][self.itemIndexTbl[row_idx]]
if itemResult.whisper and (itemResult.priceType ~= "~b/o") then
Copy(itemResult.whisper)
else
local exactQuery = dkjson.decode(self.lastQueries[row_idx])
-- use trade sum to get the specific item. both min and max
-- weight on site uses floats but only shows integer in the api
-- e.g. weight of 172.3 shows up as 172 in the api
exactQuery.query.stats[1].value = { min = floor(itemResult.weight, 1) - 1, max = round(itemResult.weight, 1) + 1 }
-- also apply trader name. this should make false positives
-- extremely unlikely. this doesn't seem to take up a filter slot
exactQuery.query.filters = exactQuery.query.filters or {}
exactQuery.query.filters.trade_filters = exactQuery.query.filters.trade_filters or { filters = {} }
exactQuery.query.filters.trade_filters.filters = exactQuery.query.filters.trade_filters.filters or {}
exactQuery.query.filters.trade_filters.filters.account = { input = itemResult.trader }

local exactQueryStr = dkjson.encode(exactQuery)

local realmPath = (self.pbRealm ~= "pc") and (self.pbRealm .. "/") or ""
local encodedUrl = s_format("https://www.pathofexile.com/trade/search/%s%s?q=%s", realmPath, urlEncode(self.pbLeague), urlEncode(exactQueryStr))

Copy(encodedUrl)
OpenURL(encodedUrl)
end
end)

controls["whisperButton" .. row_idx].tooltipFunc = function(tooltip)
tooltip:Clear()
Expand Down Expand Up @@ -1386,29 +1364,19 @@ function TradeQueryClass:UpdateRealms()

-- use trade leagues api to get trade leagues including private leagues is valid.
self.allLeagues = {}
for _, realmId in pairs (self.realmIds) do
self.tradeQueryRequests:FetchLeagues(realmId, function(leagues, errMsg)
setRealmDropList()

-- perform a generic search to make sure the authorization is valid.
if main.api.authToken then
self.tradeQueryRequests:PerformSearch("pc", "Standard", [[{"query":{"status":{"option":"online"},"stats":[{"type":"and","filters":[]}]},"sort":{"price":"asc"}}]], function(response, errMsg)
if errMsg then
self:SetNotice(self.controls.pbNotice, "Using Fallback Error while fetching league list: "..errMsg)
end
for _, league in ipairs(leagues) do
if not self.allLeagues[realmId] then self.allLeagues[realmId] = {} end
t_insert(self.allLeagues[realmId], league)
-- a 403 here likely means that the user has an outdated scope
if errMsg == "Response code: 403" then
main.api:ResetDetails()
errMsg = errMsg .. "\nPlease re-authenticate"
end
self:SetNotice(self.controls.pbNotice, "Error: " .. tostring(errMsg))
end
setRealmDropList()

end)
end

-- perform a generic search to make sure the authorization is valid.
self.tradeQueryRequests:PerformSearch("pc", "Standard", [[{"query":{"status":{"option":"online"},"stats":[{"type":"and","filters":[]}]},"sort":{"price":"asc"}}]], function(response, errMsg)
if errMsg then
-- a 403 here likely means that the user has an outdated scope
if errMsg == "Response code: 403" then
main.api:ResetDetails()
errMsg = errMsg .. "\nPlease re-authenticate"
end
self:SetNotice(self.controls.pbNotice, "Error: " .. tostring(errMsg))
end
end)
end
3 changes: 2 additions & 1 deletion src/Classes/TradeQueryRateLimiter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ function TradeQueryRateLimiterClass:TradeQueryRateLimiter()
["trade-search-request-limit"] = {},
["trade-fetch-request-limit"] = {},
["character-list-request-limit"] = {},
["character-request-limit"] = {}
["character-request-limit"] = {},
["league-request-limit"] = {},
}
return self
end
Expand Down
47 changes: 42 additions & 5 deletions src/Classes/TradeQueryRequests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,8 @@ end
---@param realm string
---@param callback fun(query:table, errMsg:string)
function TradeQueryRequestsClass:FetchLeagues(realm, callback)
local header = "Authorization: Bearer " .. (main.api.authToken or "")
launch:DownloadPage(
local function fetchStatic()
launch:DownloadPage(
self.hostName .. "api/trade/data/leagues",
function(response, errMsg)
if errMsg then
Expand All @@ -489,9 +489,46 @@ function TradeQueryRequestsClass:FetchLeagues(realm, callback)
end
end
callback(leagues, errMsg)
end,
{header = header}
)
end
)
end
if main.api.authToken then
main.api:FetchLeagues(realm, function(body, err)
-- fall back to static data on error
if not body or err then
ConPrintf("Failed to fetch oauth leagues: %s", err)
return fetchStatic()
end
if body.error then
local apiError = body.error
local errMsg = apiError or "Failed to parse trade leagues JSON"
if type(apiError) == "table" then
errMsg = apiError.message or (apiError.code and tostring(apiError.code)) or "Failed to parse trade leagues JSON"
end
ConPrintf("Failed to fetch oauth leagues: %s", errMsg)
return fetchStatic()
end
local leagues = {}
for _, value in pairs(body.leagues or {}) do
if value.rules then
-- filter out ssf leagues which might be present in the oauth query
for _, rule in ipairs(value.rules) do
if rule.id == "NoParties" then
goto skipLeague
end
end
end
table.insert(leagues, value.id)
::skipLeague::
end
if #leagues == 0 then
return fetchStatic()
end
callback(leagues, err)
end)
else
fetchStatic()
end
end

--- Build search and trade URLs with proper encoding
Expand Down
Loading