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
9 changes: 5 additions & 4 deletions spec/System/TestTradeQueryCurrency_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ describe("TradeQuery Currency Conversion", function()
-- Pass: Calculates price in divs
-- Fail: Wrong value or nil, indicating broken rounding/baseline logic
it("handles chaos currency", function()
mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 0.1 } }
mock_tradeQuery.pbCurrencyConversion = { realm = { league = { chaos = 0.1 } } }
mock_tradeQuery.pbRealm = "realm"
mock_tradeQuery.pbLeague = "league"
local result = mock_tradeQuery:ConvertCurrencyToDivs("chaos", 5)
assert.are.equal(result, 0.5)
Expand Down Expand Up @@ -67,14 +68,14 @@ describe("TradeQuery Currency Conversion", function()
assert.are.equal(result, "1 exalted, 10 div, 5 chaos")

-- check if they're sorted according to currency value
mock_tradeQuery.pbRealm = "realm"
mock_tradeQuery.pbLeague = "league"
mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 0.1, exalted = 0.05, div = 1, mirror = 700} }
mock_tradeQuery.pbCurrencyConversion = { realm = { league = { chaos = 0.1, exalted = 0.05, div = 1, mirror = 700 } } }
local result = mock_tradeQuery:GetTotalPriceString()
assert.are.equal(result, "10 div, 5 chaos, 1 exalted")

-- check that missing currency values don't crash
mock_tradeQuery.pbLeague = "league"
mock_tradeQuery.pbCurrencyConversion = { league = { chaos = 0.1, exalted = 0.05, mirror = 700 } }
mock_tradeQuery.pbCurrencyConversion = { realm = { league = { chaos = 0.1, exalted = 0.05, mirror = 700 } } }
local result = mock_tradeQuery:GetTotalPriceString()
assert.True(true)
end)
Expand Down
163 changes: 163 additions & 0 deletions spec/System/TestTradeQueryCurrency_spec.lua.rej
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
diff a/spec/System/TestTradeQueryCurrency_spec.lua b/spec/System/TestTradeQueryCurrency_spec.lua (rejected hunks)
@@ -58,6 +58,7 @@ describe("TradeQuery Currency Conversion", function()
local CHAOS = "Metadata/Items/Currency/CurrencyRerollRare"
local EXALT = "Metadata/Items/Currency/CurrencyAddModToRare"
local ALCH = "Metadata/Items/Currency/CurrencyUpgradeToRare"
+ local STACKED_DECK = "Metadata/Items/DivinationCards/DivinationCardDeck"

-- static trade data: maps display name -> short trade id
local static = {
@@ -68,35 +69,96 @@ describe("TradeQuery Currency Conversion", function()
{ id = "chaos", text = "Chaos Orb" },
{ id = "exalt", text = "Exalted Orb" },
{ id = "alch", text = "Orb of Alchemy" },
+ { id = "stacked-deck", text = "Stacked Deck" },
}
} }
}

- local origDownloadPage, origApi
+ local origDownloadPage, cxResponse

before_each(function()
mock_tradeQuery.pbRealm = "pc"
mock_tradeQuery.controls.pbNotice = {}
origDownloadPage = launch.DownloadPage
- origApi = main.api
- -- static trade data is fetched first via launch:DownloadPage
- launch.DownloadPage = function(_, _url, callback)
- callback({ body = dkjson.encode(static) })
+ cxResponse = nil
+ launch.DownloadPage = function(_, url, callback)
+ if url == "https://www.pathofexile.com/api/trade/data/static" then
+ callback({ body = dkjson.encode(static) })
+ elseif cxResponse then
+ callback({ body = dkjson.encode(cxResponse) })
+ end
end
end)

after_each(function()
launch.DownloadPage = origDownloadPage
- main.api = origApi
end)

- -- helper: make main.api:FetchCurrencyExchange feed the given markets back
- local function mockCX(markets)
- main.api = {
- FetchCurrencyExchange = function(_, _realm, callback)
- callback({ body = dkjson.encode({ markets = markets }) })
+ it("fetches currency exchange data without authentication", function()
+ local requestedUrl
+ local requestedParams
+ launch.DownloadPage = function(_, url, callback, params)
+ if url == "https://www.pathofexile.com/api/trade/data/static" then
+ callback({ body = dkjson.encode(static) })
+ else
+ requestedUrl = url
+ requestedParams = params
+ callback({ body = dkjson.encode({ markets = {} }) })
+ end
+ end
+
+ mock_tradeQuery.pbRealm = "xbox"
+ mock_tradeQuery:PullCXData()
+
+ assert.is_truthy(requestedUrl:match("^https://web%.poecdn%.com/api/currency%-exchange/xbox/%d+$"))
+ assert.is_nil(requestedParams)
+ end)
+
+ it("waits until a realm is selected", function()
+ local fetched = false
+ mock_tradeQuery.pbRealm = ""
+ launch.DownloadPage = function()
+ fetched = true
+ end
+
+ mock_tradeQuery:PullCXData()
+
+ assert.is_false(fetched)
+ end)
+
+ it("stores responses under the requested realm", function()
+ local callbacks = {}
+ launch.DownloadPage = function(_, url, callback)
+ if url == "https://www.pathofexile.com/api/trade/data/static" then
+ callback({ body = dkjson.encode(static) })
+ elseif url:find("/xbox/", 1, true) then
+ callbacks.xbox = callback
+ else
+ callbacks.pc = callback
end
- }
+ end
+
+ mock_tradeQuery.pbRealm = "pc"
+ mock_tradeQuery:PullCXData()
+ mock_tradeQuery.pbRealm = "xbox"
+ mock_tradeQuery:PullCXData()
+
+ for _, response in ipairs({ { "xbox", 5 }, { "pc", 10 } }) do
+ callbacks[response[1]]({ body = dkjson.encode({ markets = { {
+ league = "Standard",
+ market_pair = { EXALT, DIVINE },
+ lowest_ratio = { [EXALT] = response[2], [DIVINE] = 1 },
+ highest_stock = { [EXALT] = 100, [DIVINE] = 100 },
+ } } }) })
+ end
+
+ assert.are.equal(0.1, mock_tradeQuery.pbCurrencyConversion.pc.Standard.exalt)
+ assert.are.equal(0.2, mock_tradeQuery.pbCurrencyConversion.xbox.Standard.exalt)
+ end)
+
+ -- Provide the currency exchange response returned by the download mock.
+ local function mockCX(markets)
+ cxResponse = { markets = markets }
end

it("converts a chained market to divine values", function()
@@ -122,6 +184,12 @@ describe("TradeQuery Currency Conversion", function()
lowest_ratio = { [ALCH] = 5, [CHAOS] = 1 },
highest_stock = { [ALCH] = 1000, [CHAOS] = 1000 },
},
+ {
+ league = "Standard",
+ market_pair = { STACKED_DECK, DIVINE },
+ lowest_ratio = { [STACKED_DECK] = 50, [DIVINE] = 1 },
+ highest_stock = { [STACKED_DECK] = 1000, [DIVINE] = 100 },
+ },
})

mock_tradeQuery:PullCXData()
@@ -133,6 +201,7 @@ describe("TradeQuery Currency Conversion", function()
assert.are.equal(0.005, rates.chaos)
-- 0.2 chaos * 0.005 div/chaos = 0.001 div
assert.are.equal(0.001, rates.alch)
+ assert.are.equal(0.02, rates["stacked-deck"])
end)

it("keeps the highest-stock listing for a currency", function()
@@ -173,11 +242,7 @@ describe("TradeQuery Currency Conversion", function()
end)

it("shows a notice on an API error response", function()
- main.api = {
- FetchCurrencyExchange = function(_, _realm, callback)
- callback({ body = dkjson.encode({ error = { message = "kaput" } }) })
- end
- }
+ cxResponse = { error = { message = "kaput" } }

mock_tradeQuery:PullCXData()

@@ -188,9 +253,7 @@ describe("TradeQuery Currency Conversion", function()
it("does not refetch within the rate-limit window", function()
mock_tradeQuery.pbCurrencyConversion.pc = { timestamp = os.time() }
local fetched = false
- main.api = {
- FetchCurrencyExchange = function() fetched = true end
- }
+ launch.DownloadPage = function() fetched = true end

mock_tradeQuery:PullCXData()

45 changes: 45 additions & 0 deletions src/Classes/PoEAPI.lua.rej
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
diff a/src/Classes/PoEAPI.lua b/src/Classes/PoEAPI.lua (rejected hunks)
@@ -17,7 +17,6 @@ local PoEAPIClass = newClass("PoEAPI", function(self, authToken, refreshToken, t
self.refreshToken = refreshToken
self.tokenExpiry = tokenExpiry or 0
self.baseUrl = "https://api.pathofexile.com"
- self.CDNBaseUrl = "https://web.poecdn.com/api"
self.rateLimiter = new("TradeQueryRateLimiter")
self.tokenHasBeenValidated = false

@@ -152,8 +151,7 @@ end

--- @param endpoint string
--- @param callback fun(response: table?, errorMsg: string)
-function PoEAPIClass:DownloadWithRefresh(endpoint, callback, useCDN)
- local baseUrl = useCDN and self.CDNBaseUrl or self.baseUrl
+function PoEAPIClass:DownloadWithRefresh(endpoint, callback)
self:ValidateAuth(function(valid, validationErrMsg)
if not valid then
-- Clean info about token and refresh token
@@ -162,7 +160,7 @@ function PoEAPIClass:DownloadWithRefresh(endpoint, callback, useCDN)
return
end

- launch:DownloadPage(baseUrl .. endpoint, function(response, errMsg)
+ launch:DownloadPage(self.baseUrl .. endpoint, function(response, errMsg)
if errMsg and errMsg:match("401") and self.retries < 1 then
-- try once again with refresh token
self.retries = 1
@@ -234,16 +232,3 @@ function PoEAPIClass:DownloadCharacter(realm, name, callback)
self:DownloadWithRateLimit("character-request-limit",
"/character" .. (realm == "pc" and "" or "/" .. realm) .. "/" .. name, callback)
end
-
----@param realm string
----@param callback DownloadCallback
-function PoEAPIClass:FetchCurrencyExchange(realm, callback)
- local url = "/currency-exchange"
- if realm ~= "pc" then
- url = url .. "/" .. realm
- end
- local hourSeconds = 60 * 60
- local unixTimeLastHour = (math.floor(os.time() / hourSeconds) - 1) * hourSeconds
- url = url .. "/" .. unixTimeLastHour
- self:DownloadWithRefresh(url, callback, true)
-end
20 changes: 8 additions & 12 deletions src/Classes/TradeQuery.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ local TradeQueryClass = newClass("TradeQuery", function(self, itemsTab)
-- default set of trade item sort selection
self.slotTables = { }
self.pbItemSortSelectionIndex = 1
-- for each league, a table of values of each currency in div
--- @type table<string, table<string, integer>>
self.pbCurrencyConversion = { }
self.lastCurrencyConversionRequest = 0
-- for each realm and league, a table of values of each currency in div
--- @type table<string, table<string, table<string, number>>>
self.pbCurrencyConversion = {}
self.lastCurrencyFileTime = { }
self.pbFileTimestampDiff = { }
self.pbRealm = ""
Expand Down Expand Up @@ -94,7 +93,6 @@ function TradeQueryClass:PullLeagueList()
self.controls.league:SetList(self.itemsTab.leagueDropList)
self.controls.league.selIndex = 1
self.pbLeague = self.itemsTab.leagueDropList[self.controls.league.selIndex]
self:SetCurrencyConversionButton()
end
end)
end
Expand Down Expand Up @@ -382,14 +380,16 @@ Highest Weight - Displays the order retrieved from trade]]
self.controls.realmLabel = new("LabelControl", {"LEFT", self.controls.setSelect, "RIGHT"}, {18, 0, 20, row_height - 4}, "^7Realm:")
self.controls.realm = new("DropDownControl", {"LEFT", self.controls.realmLabel, "RIGHT"}, {6, 0, 150, row_height}, self.realmDropList, function(index, value)
self.pbRealmIndex = index
self.pbRealm = self.realmIds[value]
if self.pbRealm ~= self.realmIds[value] then
self.pbRealm = self.realmIds[value]
self:PullCXData()
end
local function setLeagueDropList()
self.itemsTab.leagueDropList = copyTable(self.allLeagues[self.pbRealm])
self.controls.league:SetList(self.itemsTab.leagueDropList)
-- invalidate selIndex to trigger select function call in the SetSel
self.controls.league.selIndex = nil
self.controls.league:SetSel(self.pbLeagueIndex)
self:SetCurrencyConversionButton()
end
if self.allLeagues[self.pbRealm] then
setLeagueDropList()
Expand Down Expand Up @@ -422,7 +422,6 @@ Highest Weight - Displays the order retrieved from trade]]
self.controls.league = new("DropDownControl", {"LEFT", self.controls.leagueLabel, "RIGHT"}, {6, 0, 150, row_height}, self.itemsTab.leagueDropList, function(index, value)
self.pbLeagueIndex = index
self.pbLeague = value
self:SetCurrencyConversionButton()
end)
self.controls.league:SetSel(self.pbLeagueIndex)
self.controls.league.enabled = function()
Expand Down Expand Up @@ -577,11 +576,7 @@ Highest Weight - Displays the order retrieved from trade]]
main:ClosePopup()
end)

self.controls.updateCurrencyConversion = new("ButtonControl", {"BOTTOMLEFT", nil, "BOTTOMLEFT"}, {pane_margins_horizontal, -pane_margins_vertical, 240, row_height}, "Get Currency Conversion Rates", function()
self:PullPoENinjaCurrencyConversion(self.pbLeague)
end)
self.controls.pbNotice = new("LabelControl", {"BOTTOMRIGHT", nil, "BOTTOMRIGHT"}, {-row_height - pane_margins_vertical - row_vertical_padding, -pane_margins_vertical, 300, row_height}, "")
self:SetCurrencyConversionButton()

-- used in PopupDialog:Draw()
local function scrollBarFunc()
Expand Down Expand Up @@ -615,6 +610,7 @@ Highest Weight - Displays the order retrieved from trade]]
end
end
end
self:PullCXData()
main:OpenPopup(pane_width, self.pane_height, "Trader", self.controls, nil, nil, "close", (scrollBarShown and scrollBarFunc or nil))
end

Expand Down
Loading