/trunk/ReadySpells/libs/AceComm-3.0
-- |
-- Manages AddOn chat output to keep player from getting kicked off. |
-- |
-- ChatThrottleLib:SendChatMessage/:SendAddonMessage functions that accept |
-- ChatThrottleLib:SendChatMessage/:SendAddonMessage functions that accept |
-- a Priority ("BULK", "NORMAL", "ALERT") as well as prefix for SendChatMessage. |
-- |
-- Priorities get an equal share of available bandwidth when fully loaded. |
-- LICENSE: ChatThrottleLib is released into the Public Domain |
-- |
local CTL_VERSION = 23 |
local CTL_VERSION = 24 |
local _G = _G |
----------------------------------------------------------------------- |
-- Recycling bin for pipes |
-- Recycling bin for pipes |
-- A pipe is a plain integer-indexed queue of messages |
-- Pipes normally live in Rings of pipes (3 rings total, one per priority) |
-- Initialize queues, set up frame for OnUpdate, etc |
function ChatThrottleLib:Init() |
function ChatThrottleLib:Init() |
-- Set up queues |
if not self.Prio then |
return ChatThrottleLib.Hook_SendChatMessage(...) |
end) |
--SendAddonMessage |
hooksecurefunc("SendAddonMessage", function(...) |
return ChatThrottleLib.Hook_SendAddonMessage(...) |
end) |
if _G.C_ChatInfo then |
hooksecurefunc(_G.C_ChatInfo, "SendAddonMessage", function(...) |
return ChatThrottleLib.Hook_SendAddonMessage(...) |
end) |
else |
hooksecurefunc("SendAddonMessage", function(...) |
return ChatThrottleLib.Hook_SendAddonMessage(...) |
end) |
end |
end |
self.nBypass = 0 |
end |
-- See how many of our priorities have queued messages (we only have 3, don't worry about the loop) |
local n = 0 |
for prioname,Prio in pairs(self.Prio) do |
if Prio.Ring.pos or Prio.avail < 0 then |
n = n + 1 |
if Prio.Ring.pos or Prio.avail < 0 then |
n = n + 1 |
end |
end |
local nSize = text:len(); |
if RegisterAddonMessagePrefix then |
if C_ChatInfo or RegisterAddonMessagePrefix then |
if nSize>255 then |
error("ChatThrottleLib:SendAddonMessage(): message length cannot exceed 255 bytes", 2) |
end |
if not self.bQueueing and nSize < self:UpdateAvail() then |
self.avail = self.avail - nSize |
bMyTraffic = true |
_G.SendAddonMessage(prefix, text, chattype, target) |
if _G.C_ChatInfo then |
_G.C_ChatInfo.SendAddonMessage(prefix, text, chattype, target) |
else |
_G.SendAddonMessage(prefix, text, chattype, target) |
end |
bMyTraffic = false |
self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize |
if callbackFn then |
-- Message needs to be queued |
local msg = NewMsg() |
msg.f = _G.SendAddonMessage |
msg.f = _G.C_ChatInfo and _G.C_ChatInfo.SendAddonMessage or _G.SendAddonMessage |
msg[1] = prefix |
msg[2] = text |
msg[3] = chattype |
-- It'll automatically split the messages into multiple parts and rebuild them on the receiving end.\\ |
-- **ChatThrottleLib** is of course being used to avoid being disconnected by the server. |
-- |
-- **AceComm-3.0** can be embeded into your addon, either explicitly by calling AceComm:Embed(MyAddon) or by |
-- **AceComm-3.0** can be embeded into your addon, either explicitly by calling AceComm:Embed(MyAddon) or by |
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object |
-- and can be accessed directly, without having to explicitly call AceComm itself.\\ |
-- It is recommended to embed AceComm, otherwise you'll have to specify a custom `self` on all calls you |
-- make into AceComm. |
-- @class file |
-- @name AceComm-3.0 |
-- @release $Id: AceComm-3.0.lua 1161 2017-08-12 14:30:16Z funkydude $ |
-- @release $Id: AceComm-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $ |
--[[ AceComm-3.0 |
local CallbackHandler = LibStub("CallbackHandler-1.0") |
local CTL = assert(ChatThrottleLib, "AceComm-3.0 requires ChatThrottleLib") |
local MAJOR, MINOR = "AceComm-3.0", 10 |
local MAJOR, MINOR = "AceComm-3.0", 12 |
local AceComm,oldminor = LibStub:NewLibrary(MAJOR, MINOR) |
if not AceComm then return end |
AceComm.multipart_reassemblers = nil |
-- the multipart message spool: indexed by a combination of sender+distribution+ |
AceComm.multipart_spool = AceComm.multipart_spool or {} |
AceComm.multipart_spool = AceComm.multipart_spool or {} |
--- Register for Addon Traffic on a specified prefix |
-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent), max 16 characters |
if #prefix > 16 then -- TODO: 15? |
error("AceComm:RegisterComm(prefix,method): prefix length is limited to 16 characters") |
end |
RegisterAddonMessagePrefix(prefix) |
if C_ChatInfo then |
C_ChatInfo.RegisterAddonMessagePrefix(prefix) |
else |
RegisterAddonMessagePrefix(prefix) |
end |
return AceComm._RegisterComm(self, prefix, method) -- created by CallbackHandler |
end |
if not( type(prefix)=="string" and |
type(text)=="string" and |
type(distribution)=="string" and |
(target==nil or type(target)=="string") and |
(prio=="BULK" or prio=="NORMAL" or prio=="ALERT") |
(target==nil or type(target)=="string" or type(target)=="number") and |
(prio=="BULK" or prio=="NORMAL" or prio=="ALERT") |
) then |
error('Usage: SendCommMessage(addon, "prefix", "text", "distribution"[, "target"[, "prio"[, callbackFn, callbackarg]]])', 2) |
end |
return callbackFn(callbackArg, sent, textlen) |
end |
end |
local forceMultipart |
if match(text, "^[\001-\009]") then -- 4.1+: see if the first character is a control character |
-- we need to escape the first character with a \004 |
local compost = setmetatable({}, {__mode = "k"}) |
local function new() |
local t = next(compost) |
if t then |
if t then |
compost[t]=nil |
for i=#t,3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten |
t[i]=nil |
end |
return t |
end |
return {} |
end |
local function lostdatawarning(prefix,sender,where) |
DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: lost network data regarding '"..tostring(prefix).."' from '"..tostring(sender).."' (in "..where..")") |
end |
function AceComm:OnReceiveMultipartFirst(prefix, message, distribution, sender) |
local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender |
local spool = AceComm.multipart_spool |
--[[ |
if spool[key] then |
if spool[key] then |
lostdatawarning(prefix,sender,"First") |
-- continue and overwrite |
end |
--]] |
spool[key] = message -- plain string for now |
end |
local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender |
local spool = AceComm.multipart_spool |
local olddata = spool[key] |
if not olddata then |
--lostdatawarning(prefix,sender,"Next") |
return |
local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender |
local spool = AceComm.multipart_spool |
local olddata = spool[key] |
if not olddata then |
--lostdatawarning(prefix,sender,"End") |
return |
end |
spool[key] = nil |
if type(olddata) == "table" then |
-- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat |
tinsert(olddata, message) |