From cd22c710b225a87085bab1eab18f798ce3d8f284 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 12 Oct 2024 01:04:27 +0100 Subject: [PATCH] start working on implementing some kind of system to catch error messages ....it works, but: - We can't capture stack traces like this - It's messy - We need to implement an escape/encodeURIComponent function ourselves from scratch 'cause the one I ripped from Stack Overflow sucks --- worldeditadditions_core/core/run_command.lua | 64 ++++++++++++++++++- worldeditadditions_core/init.lua | 23 ++++++- .../utils/format/escape.lua | 18 ++++++ worldeditadditions_core/utils/format/init.lua | 1 + .../utils/setting_handler.lua | 4 +- .../utils/strings/split.lua | 2 +- 6 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 worldeditadditions_core/utils/format/escape.lua diff --git a/worldeditadditions_core/core/run_command.lua b/worldeditadditions_core/core/run_command.lua index 8dfbce6..a2bac27 100644 --- a/worldeditadditions_core/core/run_command.lua +++ b/worldeditadditions_core/core/run_command.lua @@ -8,7 +8,7 @@ local human_size = wea_c.format.human_size -- TODO: Reimplement worldedit.player_notify(player_name, msg_text) ---- Actually runs the command in question. +--- Actually runs the command in question. [HIDDEN] -- Unfortunately needed to keep the codebase clena because Lua sucks. -- @internal -- @param player_name string The name of the player executing the function. @@ -34,6 +34,51 @@ local function run_command_stage2(player_name, func, parse_result, tbl_event) wea_c:emit("post-execute", tbl_event) end +local function send_error(player_name, cmdname, msg, stack_trace) + print("DEBUG:HAI SEND_ERROR") + local msg_compiled = table.concat({ + "[//", cmdname, "] Error: ", + msg, + "\n", + "Please report this by opening an issue on GitHub! Bug report link:\n", + "https://github.com/sbrl/Minetest-WorldEditAdditions/issues/new?title=", + wea_c.format.escape(stack_trace:match("^[^\n]+")), -- extract 1st line & escape + "&body=", + wea_c.format.escape([[## Describe the bug +What's the bug? Be clear and detailed but concise in our explanation. Don't forget to include any context, error messages, logs, and screenshots required to understand the issue if applicable. + +## Reproduction steps +Steps to reproduce the behaviour: +1. Go to '...' +2. Click on '....' +3. Enter this command to '....' +4. See error + +## System information (please complete the following information) +- **Operating system and version:** [e.g. iOS] +- **Minetest version:** [e.g. 5.8.0] +- **WorldEdit version:** +- **WorldEditAdditions version:** + +Please add any other additional specific system information here too if you think it would help. + +## Stack trace +- Command name: ]]), + wea_c.format.escape(cmdname), + wea_c.format.escape("```\n"), + wea_c.format.escape(stack_trace), + wea_c.format.escape("\n```"), + "-------------------------------------\n", + "*** Stack trace ***\n", + stack_trace, + "\n", + "-------------------------------------" + }, "") + + print("DEBUG:player_notify player_name", player_name, "msg_compiled", msg_compiled) + worldedit.player_notify(player_name, msg_compiled) +end + --- Command execution pipeline: before `paramtext` parsing but after validation. -- -- See `worldeditadditions_core.run_command` @@ -112,7 +157,22 @@ local function run_command(cmdname, options, player_name, paramtext) wea_c:emit("pre-parse", tbl_event) - local parse_result = { options.parse(paramtext) } + local parse_result, error_message + local did_error = false + xpcall(function() + parse_result = { options.parse(paramtext)} + end, function(error_raw) + did_error = true + error_message = error_raw + print("DEBUG:parse_result>>error", error_raw, "stack trace", debug.traceback()) + end) + if did_error then + print("DEBUG:parse_result EXIT_DUE_TO_ERROR") + send_error(player_name, cmdname, "The command crashed when parsing the arguments.", error_message) + print("DEBUG:parse_result EXIT_DUE_TO_ERROR __final_call__") + return false + end -- handling is wrapped with xpcall() + local success = table.remove(parse_result, 1) if not success then worldedit.player_notify(player_name, ("[//"..tostring(cmdname).."] "..tostring(parse_result[1])) or "Invalid usage (no further error message was provided by the command. This is probably a bug.)") diff --git a/worldeditadditions_core/init.lua b/worldeditadditions_core/init.lua index d2463ef..c58f545 100644 --- a/worldeditadditions_core/init.lua +++ b/worldeditadditions_core/init.lua @@ -11,14 +11,33 @@ local modpath = minetest.get_modpath("worldeditadditions_core") local EventEmitter = dofile(modpath .. "/utils/EventEmitter.lua") +local directory_separator = "/" +if package and package.config then + directory_separator = package.config:sub(1,1) +end + worldeditadditions_core = EventEmitter.new({ version = "1.15-dev", + --- The directory separator on the current host system + -- @value string + dirsep = directory_separator, + --- The full absolute filepath to the mod worldeditadditions_core + -- @value modpath = modpath, + --- The full absolute filepath to the data directory WorldEditAdditions can store miscellaneous data in. + -- @value + datapath = minetest.get_worldpath() .. directory_separator .."worldeditadditions", + --- A table containing the definitions for all commands registered in WorldEditAdditions. + -- Keys are the command name SANS any forward slashes! So //replacemix would be registered as simply replacemix. + -- @value table registered_commands = {}, - -- Storage for per-player node limits before safe_region kicks in. + --- Storage for per-player node limits before safe_region kicks in. -- TODO: Persist these to disk. + -- @value table safe_region_limits = {}, - -- The default limit for new players on the number of potential nodes changed before safe_region kicks in. + --- The default limit for new players on the number of potential nodes changed before safe_region kicks in. + -- TODO make this configurable + -- @value number safe_region_limit_default = 100000, }) local wea_c = worldeditadditions_core diff --git a/worldeditadditions_core/utils/format/escape.lua b/worldeditadditions_core/utils/format/escape.lua new file mode 100644 index 0000000..42b2baa --- /dev/null +++ b/worldeditadditions_core/utils/format/escape.lua @@ -0,0 +1,18 @@ +--- +-- @module worldeditadditions_core + +-- decodeURIComponent() implementation +-- Ref https://stackoverflow.com/a/78225561/1460422 + +-- TODO this doesn't work. It replaces \n with %A instead of %0A, though we don't know if that's a problem or not +-- it also doesn't handle quotes even though we've clearly got them in the Lua pattern +local function _escape_char(char) + print("_escape_char char", char, "result", string.format('%%%0X', string.byte(char))) + return string.format('%%%0X', string.byte(char)) +end + +local function escape(uri) + return (string.gsub(uri, "[^%a%d%-_%.!~%*'%(%);/%?:@&=%+%$,#]", _escape_char)) +end + +return escape \ No newline at end of file diff --git a/worldeditadditions_core/utils/format/init.lua b/worldeditadditions_core/utils/format/init.lua index 363eebd..4e2b4ee 100644 --- a/worldeditadditions_core/utils/format/init.lua +++ b/worldeditadditions_core/utils/format/init.lua @@ -8,5 +8,6 @@ wea_c.format = { node_distribution = dofile(wea_c.modpath.."/utils/format/node_distribution.lua"), make_ascii_table = dofile(wea_c.modpath.."/utils/format/make_ascii_table.lua"), map = dofile(wea_c.modpath.."/utils/format/map.lua"), + escape = dofile(wea_c.modpath.."/utils/format/escape.lua") } diff --git a/worldeditadditions_core/utils/setting_handler.lua b/worldeditadditions_core/utils/setting_handler.lua index 25d0081..4ded5aa 100644 --- a/worldeditadditions_core/utils/setting_handler.lua +++ b/worldeditadditions_core/utils/setting_handler.lua @@ -4,10 +4,10 @@ local wea_c = worldeditadditions_core wea_c.settings = {} -- Initialize wea world folder if not already existing -local path = minetest.get_worldpath() .. "/worldeditadditions" +local path = minetest.get_worldpath() .. wea_c.dirsep .. "worldeditadditions" minetest.mkdir(path) ---- A wrapper to simultaniously handle global and world settings. +--- A wrapper to simultaneously handle global and world settings. -- @namespace worldeditadditions_core.setting_handler local setting_handler = {} diff --git a/worldeditadditions_core/utils/strings/split.lua b/worldeditadditions_core/utils/strings/split.lua index 1e1ff60..2bf64c9 100644 --- a/worldeditadditions_core/utils/strings/split.lua +++ b/worldeditadditions_core/utils/strings/split.lua @@ -62,7 +62,7 @@ end -- @param plain boolean If true (or truthy), pattern is interpreted as a -- plain string, not a Lua pattern -- @returns table A sequence table containing the substrings -local function split(str,dlm,plain) +local function split(str, dlm, plain) if not dlm then dlm = "%s+" end local pos, ret = 0, {} local ins, i = str:find(dlm,pos,plain)