Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle throttle return codes from send APIs #55

Merged
merged 9 commits into from
Apr 29, 2024
Merged
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
2 changes: 2 additions & 0 deletions .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ read_globals = {
"C_ReportSystem.CanReportPlayer",
"C_ReportSystem.OpenReportPlayerDialog",
"C_Timer.After",
"C_Timer.NewTicker",
"CallErrorHandler",
"ChatFrame_AddMessageEventFilter",
"CreateFrame",
"CreateFromMixins",
"DoublyLinkedListMixin",
"Enum.SendAddonMessageResult",
"ERR_CHAT_PLAYER_NOT_FOUND_S",
"FULL_PLAYER_NAME",
"GetAutoCompleteRealms",
Expand Down
99 changes: 71 additions & 28 deletions Internal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
]]

local VERSION = 24
local VERSION = 25

if IsLoggedIn() then
error(("Chomp Message Library (embedded: %s) cannot be loaded after login."):format((...)))
Expand Down Expand Up @@ -278,51 +278,102 @@ end
INTERNAL BANDWIDTH POOL
]]

local SendAddonMessageResult = Mixin({
Success = 0,
InvalidPrefix = 1,
InvalidMessage = 2,
AddonMessageThrottle = 3,
InvalidChatType = 4,
NotInGroup = 5,
TargetRequired = 6,
InvalidChannel = 7,
ChannelThrottle = 8,
GeneralError = 9, -- Reporting for duty, sir!
}, Enum.SendAddonMessageResult or {})

function Internal:MapToSendAddonMessageResult(result)
if result == true then
result = SendAddonMessageResult.Success
elseif result == false then
result = SendAddonMessageResult.GeneralError
end

return result
end

function Internal:IsRetryMessageResult(result)
if result == SendAddonMessageResult.AddonMessageThrottle then
return true
elseif result == SendAddonMessageResult.ChannelThrottle then
return true
else
return false
end
end

function Internal:RunQueue()
if self:UpdateBytes() <= 0 then
return
end
local active = {}
local blockedQueues = {}
for i, priority in ipairs(PRIORITIES) do
if self[priority].front then -- Priority has queues.
active[#active + 1] = self[priority]
end
end
local remaining = #active
local bytes = self.bytes / remaining
local bytes = (#active > 0 and self.bytes / #active or 0)
self.bytes = 0
for i, priority in ipairs(active) do
priority.bytes = priority.bytes + bytes
while priority.front and priority.bytes >= priority.front.front.length do
local queue = priority:PopFront()
local message = queue:PopFront()
if queue.front then -- More messages in this queue.
priority:PushBack(queue)
else -- No more messages in this queue.
priority.byName[queue.name] = nil
end
local didSend = false
local sendResult = SendAddonMessageResult.GeneralError
if (message.kind ~= "RAID" and message.kind ~= "PARTY" or IsInGroup(LE_PARTY_CATEGORY_HOME)) and (message.kind ~= "INSTANCE_CHAT" or IsInGroup(LE_PARTY_CATEGORY_INSTANCE)) then
priority.bytes = priority.bytes - message.length
self.isSending = true
didSend = message.f(unpack(message, 1, 4)) ~= false
sendResult = self:MapToSendAddonMessageResult(select(-1, true, message.f(unpack(message, 1, 4))))
self.isSending = false
end
if message.callback then
xpcall(message.callback, CallErrorHandler, message.callbackArg, didSend)
if self:IsRetryMessageResult(sendResult) then
-- Requeue the message, but don't requeue the queue.
queue:PushFront(message)
priority.bytes = priority.bytes + message.length
blockedQueues[#blockedQueues + 1] = { priority, queue }
else
if queue.front then -- More messages in this queue.
priority:PushBack(queue)
else -- No more messages in this queue.
priority.byName[queue.name] = nil
end
if message.callback then
local didSend = (sendResult == SendAddonMessageResult.Success)
xpcall(message.callback, CallErrorHandler, message.callbackArg, didSend)
end
end
end
if not priority.front then
remaining = remaining - 1
self.bytes = self.bytes + priority.bytes
priority.bytes = 0
end
end
if remaining == 0 then
self.hasQueue = nil
for _, blockedQueueInfo in ipairs(blockedQueues) do
local priority, queue = unpack(blockedQueueInfo)
priority:PushBack(queue)
end
end

function Internal:HasQueuedData()
for _, priority in ipairs(PRIORITIES) do
if self[priority].front then
return true;
end
end

return false;
end

function Internal:UpdateBytes()
local bps, burst = self.BPS, self.BURST
if InCombatLockdown() then
Expand Down Expand Up @@ -362,20 +413,12 @@ for i, priority in ipairs(PRIORITIES) do
end

function Internal:StartQueue()
if not self.hasQueue then
self.hasQueue = true
C_Timer.After(POOL_TICK, self.OnTick)
end
end
if not self.queueTicker then
local function OnTick()
self:RunQueue()
end

function Internal.OnTick()
local self = Internal
if not self.hasQueue then
return
end
self:RunQueue()
if self.hasQueue then
C_Timer.After(POOL_TICK, self.OnTick)
self.queueTicker = C_Timer.NewTicker(POOL_TICK, OnTick)
end
end

Expand Down
32 changes: 19 additions & 13 deletions Public.lua
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,18 @@ function Chomp.SendAddonMessage(prefix, text, kind, target, priority, queue, cal
return
end

if not Internal.hasQueue and length <= Internal:UpdateBytes() then
if not Internal:HasQueuedData() and length <= Internal:UpdateBytes() then
Internal.bytes = Internal.bytes - length
Internal.isSending = true
C_ChatInfo.SendAddonMessage(prefix, text, kind, target)
local sendResult = select(-1, C_ChatInfo.SendAddonMessage(prefix, text, kind, target))
sendResult = Internal:MapToSendAddonMessageResult(sendResult)
Internal.isSending = false
if callback then
xpcall(callback, CallErrorHandler, callbackArg, true)
if not Internal:IsRetryMessageResult(sendResult) then
if callback then
xpcall(callback, CallErrorHandler, callbackArg, true)
end
return
end
return
end

local message = {
Expand Down Expand Up @@ -160,15 +163,18 @@ function Chomp.SendAddonMessageLogged(prefix, text, kind, target, priority, queu
return
end

if not Internal.hasQueue and length <= Internal:UpdateBytes() then
if not Internal:HasQueuedData() and length <= Internal:UpdateBytes() then
Internal.bytes = Internal.bytes - length
Internal.isSending = true
C_ChatInfo.SendAddonMessageLogged(prefix, text, kind, target)
local sendResult = select(-1, C_ChatInfo.SendAddonMessageLogged(prefix, text, kind, target))
sendResult = Internal:MapToSendAddonMessageResult(sendResult)
Internal.isSending = false
if callback then
xpcall(callback, CallErrorHandler, callbackArg, true)
if not Internal:IsRetryMessageResult(sendResult) then
if callback then
xpcall(callback, CallErrorHandler, callbackArg, true)
end
return
end
return
end

local message = {
Expand Down Expand Up @@ -232,7 +238,7 @@ function Chomp.SendChatMessage(text, kind, language, target, priority, queue, ca
return
end

if not Internal.hasQueue and length <= Internal:UpdateBytes() then
if not Internal:HasQueuedData() and length <= Internal:UpdateBytes() then
Internal.bytes = Internal.bytes - length
Internal.isSending = true
SendChatMessage(text, kind, language, target)
Expand Down Expand Up @@ -287,7 +293,7 @@ function Chomp.BNSendGameData(bnetIDGameAccount, prefix, text, priority, queue,

length = length + 18 -- 16 byte prefix, 2 byte bnetIDAccount

if not Internal.hasQueue and length <= Internal:UpdateBytes() then
if not Internal:HasQueuedData() and length <= Internal:UpdateBytes() then
Internal.bytes = Internal.bytes - length
Internal.isSending = true
BNSendGameData(bnetIDGameAccount, prefix, text)
Expand Down Expand Up @@ -336,7 +342,7 @@ function Chomp.BNSendWhisper(bnetIDAccount, text, priority, queue, callback, cal

length = length + 2 -- 2 byte bnetIDAccount

if not Internal.hasQueue and length <= Internal:UpdateBytes() then
if not Internal:HasQueuedData() and length <= Internal:UpdateBytes() then
Internal.bytes = Internal.bytes - length
Internal.isSending = true
BNSendWhisper(bnetIDAccount, text)
Expand Down
Loading