Advertisement
Guest User

Untitled

a guest
Jun 4th, 2011
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.98 KB | None | 0 0
  1. -- Yes, hi, this file is plaintext and you are reading it! If you can find a way to break it, please let us know.
  2.  
  3. -- These files are all wrapped in a setfenv so we don't accidentally pollute the global table (and, conversely, so the global table can't be changed to muck with us.)
  4. -- We're not importing _G in implicitly via metatable because we don't want to rely on it for *anything* - every import needs to be cached locally, before user addons can get in and start replacing functions.
  5. -- In reality, even if this all existed in userspace, we'd still be "safe" - the addon environment just doesn't have the hooks exposed to do anything sensitive - but I have no interest in debugging problems caused by somebody reimplementing ipairs or select.
  6.  
  7.  
  8. local addonLookupTable
  9. local errorEventSpawner
  10. local performanceStackPush
  11. local performanceStackPop
  12.  
  13. function setEventFunctions(alt, ees, pspush, pspop)
  14.   addonLookupTable = alt
  15.   errorEventSpawner = ees
  16.   performanceStackPush = pspush
  17.   performanceStackPop = pspop
  18. end
  19.  
  20. local ipairs = _G.ipairs
  21. local xpcall = _G.xpcall
  22. local print = _G.print
  23. local assert = _G.assert
  24. local error = _G.error
  25. local type = _G.type
  26. local select = _G.select
  27. local unpack = _G.unpack
  28. local gmatch = _G.string.gmatch
  29. local rawget = _G.rawget
  30. local gsub = _G.string.gsub
  31. local format = _G.string.format
  32. local tinsert = _G.table.insert
  33. local loadstring = _G.loadstring
  34. local traceback = _G.debug.traceback
  35. local tostring = _G.tostring
  36. local collectgarbage = _G.collectgarbage
  37.  
  38. -- Set this up now, we'll fill it via eventRegister
  39. _G.Event = {}
  40.  
  41. local eventNameLookup = {}
  42. function traverseAndCreate(eventname)
  43.   local eventtable = _G.Event
  44.  
  45.   -- Traverse down the tree based on our event name
  46.   for word in gmatch(eventname, "([^_]+)") do
  47.     if not eventtable[word] then
  48.       eventtable[word] = {}
  49.     end
  50.    
  51.     eventtable = eventtable[word]
  52.   end
  53.  
  54.   return eventtable
  55. end
  56. function eventRegister(eventname)
  57.   local eventtable = traverseAndCreate(eventname)
  58.  
  59.   -- Add an entry to our lookup table
  60.   eventNameLookup[eventtable] = gsub(eventname, "_", ".")
  61.  
  62.   documentedObjects[gsub(eventname, "_", ".")] = {eventtable, "(Event documentation TBI)"}
  63.   documentedObjectLookup[eventtable] = gsub(eventname, "_", ".")
  64.  
  65.   return eventtable
  66. end
  67. function slashRegister(slashname)
  68.   -- We can't use the traverseAndCreate function because we might have actual underscores, so we'll do something a little hacky
  69.   local eventtable = traverseAndCreate("Slash")
  70.  
  71.   assert(not eventtable[slashname])
  72.   eventtable[slashname] = {}
  73.   eventtable = eventtable[slashname]
  74.  
  75.   eventNameLookup[eventtable] = "Slash." .. slashname
  76.  
  77.   documentedObjects["Event.Slash." .. slashname] = {eventtable, "(Slash event documentation TBI)"}
  78.   documentedObjectLookup[eventtable] = "Event.Slash." .. slashname
  79.  
  80.   return eventtable
  81. end
  82.  
  83. -- We make this so we can have the stub in place
  84. traverseAndCreate("Slash")
  85.  
  86. -- Since errors spawn events, but events can spawn errors, we put a little test here. If we end up in a recursive error, we drop out.
  87. -- We do permit one extra stack depth to make it easier to debug error handlers, however ;)
  88. local errorHandlerDepth = 0
  89. function errorHandler(event_name, traceback, hook, err)
  90.   if errorHandlerDepth > 1 then return end
  91.   errorHandlerDepth = errorHandlerDepth + 1
  92.  
  93.   errorEventSpawner(event_name, rawget(hook, 2), rawget(hook, 3), err, traceback)
  94.  
  95.   errorHandlerDepth = errorHandlerDepth - 1
  96. end
  97.  
  98. function eventHookDispatcher(eventtable, ...)
  99.   local parameters = {...}
  100.   local parametercount = select("#", ...)
  101.  
  102.   -- We wrap this in an xpcall in case someone's done something nasty to the hooktable metatable
  103.   local success, result = xpcall(function ()
  104.     for _, v in ipairs(eventtable) do
  105.    
  106.       local pushed = false
  107.      
  108.       -- And we wrap the individual calls in xpcalls so that an error in one addon won't trash other addons
  109.       local success, result = xpcall(function ()
  110.         -- We want to be able to identify our own hooks as ours, but still not let other people masquerade as us
  111.         -- Right now we're just ignoring the second half of that. We can always retrofit that into the system in a patch.
  112.         local privileged = (rawget(v, 2) == "Rift")
  113.        
  114.         -- The table we've been given may have some metatable craziness so we use raw gets for everything, as we want to be able to report data accurately
  115.         -- Verify that the hook is set up correctly (if it's not, we'll just mash the error handler)
  116.         if type(rawget(v, 2)) ~= "string" then
  117.           error(format("Event hook in %s has a addon identifier of type %s, not string", eventNameLookup[eventtable], type(rawget(v, 2))))
  118.         end
  119.         if not addonLookupTable[rawget(v, 2)] and not privileged then
  120.           error(format("Event hook in %s refers to an unknown addon \"%s\"", eventNameLookup[eventtable], rawget(v, 2)))
  121.         end
  122.         if type(rawget(v, 3)) ~= "string" then
  123.           error(format("Event hook in %s has a hook identifier of type %s, not string", eventNameLookup[eventtable], type(rawget(v, 3))))
  124.         end
  125.        
  126.         -- Push a stack in the performance monitor
  127.         performanceStackPush(rawget(v, 2), rawget(v, 3))
  128.         pushed = true
  129.        
  130.         -- Returning values is currently an error, so we don't permit it.
  131.         assert(select("#", rawget(v, 1)(unpack(parameters, 1, parametercount))) == 0)
  132.       end, function (err)
  133.         return {traceback = traceback(), err = err}
  134.       end)
  135.      
  136.       if pushed then
  137.         -- Pop that stack
  138.         performanceStackPop()
  139.       end
  140.      
  141.       if not success then
  142.         errorHandler(eventNameLookup[eventtable], result.traceback, v, result.err)
  143.       end
  144.      
  145.     end
  146.   end, function (err)
  147.     return {traceback = traceback(), err = err}
  148.   end)
  149.  
  150.   if not success then
  151.     errorHandler(eventNameLookup[eventtable], result.traceback, {nil, "Rift", eventNameLookup[eventtable] .. " table iteration"}, result.err)
  152.   end
  153. end
  154. function frameEventHookDispatcher(frameTable, eventTable, handle, owner, ident)
  155.   local func = rawget(eventTable, handle)
  156.   if func == nil then
  157.     return false
  158.   end
  159.  
  160.   local success, result = xpcall(function ()
  161.     assert(select("#", func(frameTable)) == 0)
  162.   end, function (err)
  163.     return {traceback = traceback(), err = err}
  164.   end)
  165.  
  166.   if not success then
  167.     errorHandler(ident, result.traceback, {nil, owner, handle}, result.err)
  168.   end
  169.  
  170.   return true -- even if we have an error, because if the error is fixed, we won't get a notification
  171. end
  172.  
  173. function runString(str)
  174.   local success, result = xpcall(function ()
  175.     assert(loadstring(str))()
  176.   end, function (err)
  177.     return {traceback = traceback(), err = err}
  178.   end)
  179.  
  180.   if not success then
  181.     errorHandler("Console", result.traceback, {nil, "Rift", str}, result.err)
  182.   end
  183. end
  184.  
  185. -- Runs a pre-supplied function that's been generated from a file
  186. function runFile(addonIdentifier, func)
  187.   local success, result = xpcall(function ()
  188.     assert(select("#", func()) == 0)
  189.   end, function (err)
  190.     return {traceback = traceback(), err = err}
  191.   end)
  192.  
  193.   if not success then
  194.     errorHandler("Load", result.traceback, {nil, addonIdentifier, "Run"}, result.err)
  195.   end
  196. end
  197.  
  198. local function safetostring(param)
  199.   if type(param) == "string" or type(param) == "number" then
  200.     return tostring(param)
  201.   else
  202.     return type(param)
  203.   end
  204. end
  205. function insertDefaultEvents()
  206.   -- System error handler
  207.   tinsert(_G.Event.System.Error, {function (err, event, addon, hook, traceback)
  208.     print("---------")
  209.     print("Error: " .. safetostring(err))
  210.     print(format("    In %s / %s, event %s", safetostring(addon), safetostring(hook), safetostring(event)))
  211.     print(safetostring(traceback))
  212.   end, "Rift", "Default error hook"})
  213.  
  214.   -- System garbage collector
  215.   tinsert(_G.Event.System.Update.End, {function ()
  216.     collectgarbage("stop")
  217.     collectgarbage("step", 1)
  218.   end, "Rift", "Garbage Collector"})
  219. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement