Hook.lua (5083B)
1 -- Hook.lua - Event hook system for LuajitOS 2 -- Allows registering and running event callbacks with priority and control flow 3 4 local Hook = { 5 instances = {} 6 } 7 8 -- Create a new hook instance 9 -- Returns a new hook object with add, remove, and run methods 10 function Hook.newInstance() 11 local instance = { 12 hooks = {} -- Structure: { [eventName] = { {name=hookName, func=callback}, ... } } 13 } 14 15 -- Add a hook for an event 16 -- @param eventName: The name of the event to hook into 17 -- @param hookName: Unique identifier for this hook 18 -- @param callback: Function to call when event is triggered 19 function instance:add(eventName, hookName, callback) 20 if type(eventName) ~= "string" or eventName == "" then 21 error("Hook.add: eventName must be a non-empty string") 22 end 23 24 if type(hookName) ~= "string" or hookName == "" then 25 error("Hook.add: hookName must be a non-empty string") 26 end 27 28 if type(callback) ~= "function" then 29 error("Hook.add: callback must be a function") 30 end 31 32 -- Initialize event hook list if it doesn't exist 33 if not self.hooks[eventName] then 34 self.hooks[eventName] = {} 35 end 36 37 -- Check if hook with this name already exists for this event 38 for i, hook in ipairs(self.hooks[eventName]) do 39 if hook.name == hookName then 40 -- Replace existing hook 41 hook.func = callback 42 return 43 end 44 end 45 46 -- Add new hook 47 table.insert(self.hooks[eventName], { 48 name = hookName, 49 func = callback 50 }) 51 end 52 53 -- Remove hook(s) from an event 54 -- @param eventName: The name of the event 55 -- @param hookName: (optional) Specific hook name to remove. If nil, removes all hooks for the event 56 function instance:remove(eventName, hookName) 57 if type(eventName) ~= "string" or eventName == "" then 58 error("Hook.remove: eventName must be a non-empty string") 59 end 60 61 if not self.hooks[eventName] then 62 return -- No hooks for this event 63 end 64 65 if hookName == nil then 66 -- Remove all hooks for this event 67 self.hooks[eventName] = nil 68 else 69 -- Remove specific hook 70 if type(hookName) ~= "string" then 71 error("Hook.remove: hookName must be a string or nil") 72 end 73 74 for i = #self.hooks[eventName], 1, -1 do 75 if self.hooks[eventName][i].name == hookName then 76 table.remove(self.hooks[eventName], i) 77 break 78 end 79 end 80 81 -- Clean up empty event table 82 if #self.hooks[eventName] == 0 then 83 self.hooks[eventName] = nil 84 end 85 end 86 end 87 88 -- Run all hooks for an event 89 -- @param eventName: The name of the event to trigger 90 -- @param ...: Arguments to pass to each hook callback 91 -- @return: true if any hook returned true (stopping execution), false otherwise 92 function instance:run(eventName, ...) 93 if type(eventName) ~= "string" or eventName == "" then 94 error("Hook.run: eventName must be a non-empty string") 95 end 96 97 if not self.hooks[eventName] then 98 return false -- No hooks for this event 99 end 100 101 -- Run each hook in order 102 for i, hook in ipairs(self.hooks[eventName]) do 103 local success, result = pcall(hook.func, ...) 104 105 if not success then 106 -- Hook threw an error - log it but continue 107 if osprint then 108 osprint("Hook error in '" .. eventName .. "' hook '" .. hook.name .. "': " .. tostring(result)) 109 end 110 elseif result == true then 111 -- Hook returned true - stop executing remaining hooks 112 return true 113 end 114 end 115 116 return false 117 end 118 119 -- Get all hook names for an event 120 -- @param eventName: The name of the event 121 -- @return: Array of hook names, or empty array if no hooks 122 function instance:getHooks(eventName) 123 if type(eventName) ~= "string" or eventName == "" then 124 error("Hook.getHooks: eventName must be a non-empty string") 125 end 126 127 if not self.hooks[eventName] then 128 return {} 129 end 130 131 local names = {} 132 for i, hook in ipairs(self.hooks[eventName]) do 133 table.insert(names, hook.name) 134 end 135 136 return names 137 end 138 139 -- Get all event names that have hooks 140 -- @return: Array of event names 141 function instance:getEvents() 142 local events = {} 143 for eventName, _ in pairs(self.hooks) do 144 table.insert(events, eventName) 145 end 146 return events 147 end 148 149 -- Clear all hooks from this instance 150 function instance:clear() 151 self.hooks = {} 152 end 153 154 -- Store instance 155 table.insert(Hook.instances, instance) 156 157 return instance 158 end 159 160 return Hook