Mercurial > prosody-hg
comparison plugins/mod_admin_shell.lua @ 14115:44a8c8d4146a
Merge 13.0->trunk
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Tue, 31 Mar 2026 12:25:20 +0100 |
| parents | f20bb1c53652 b9688ac25255 |
| children | 7008869fcce2 |
comparison
equal
deleted
inserted
replaced
| 14112:59064f0f8b4e | 14115:44a8c8d4146a |
|---|---|
| 2897 | 2897 |
| 2898 -- host_commands[section..":"..name][host] = handler | 2898 -- host_commands[section..":"..name][host] = handler |
| 2899 -- host_commands[section..":"..name][false] = metadata | 2899 -- host_commands[section..":"..name][false] = metadata |
| 2900 local host_commands = {}; | 2900 local host_commands = {}; |
| 2901 | 2901 |
| 2902 -- Remove command handlers for a host (specify name to clear just one command) | |
| 2903 function clear_host_commands(host, name) | |
| 2904 for command_name, command_info in pairs(host_commands) do | |
| 2905 if not name or name == command_name then | |
| 2906 command_info[host] = nil; | |
| 2907 local has_any_host_handlers_left; | |
| 2908 for k in pairs(command_info) do | |
| 2909 if k ~= false then | |
| 2910 has_any_host_handlers_left = true; | |
| 2911 break; | |
| 2912 end | |
| 2913 end | |
| 2914 if not has_any_host_handlers_left then | |
| 2915 host_commands[command_name] = nil; | |
| 2916 end | |
| 2917 if name then | |
| 2918 break; | |
| 2919 end | |
| 2920 end | |
| 2921 end | |
| 2922 end | |
| 2923 | |
| 2924 -- This returns a wrapper function which routes to the correct handler for a host | |
| 2925 local function new_host_command_handler(qualified_name, selector_name, selector_index) | |
| 2926 return function (...) | |
| 2927 local selected_host = select(2, jid_split((select(selector_index, ...)))); | |
| 2928 if type(selected_host) ~= "string" then | |
| 2929 return nil, "Invalid or missing argument '"..selector_name.."'"; | |
| 2930 end | |
| 2931 if not prosody.hosts[selected_host] then | |
| 2932 return nil, "Unknown host: "..selected_host; | |
| 2933 end | |
| 2934 local host_handler = host_commands[qualified_name][selected_host]; | |
| 2935 if not host_handler then | |
| 2936 return nil, "This command is not available on "..selected_host; | |
| 2937 end | |
| 2938 return host_handler(...); | |
| 2939 end; | |
| 2940 end | |
| 2941 | |
| 2902 local function new_item_handlers(command_host) | 2942 local function new_item_handlers(command_host) |
| 2903 local function on_command_added(event) | 2943 local function on_command_added(event) |
| 2904 local command = event.item; | 2944 local command = event.item; |
| 2905 local mod_name = event.source and ("mod_"..event.source.name) or "<unknown module>"; | 2945 local mod_name = event.source and ("mod_"..event.source.name) or "<unknown module>"; |
| 2906 if not schema.validate(command_metadata_schema, command) or type(command.handler) ~= "function" then | 2946 if not schema.validate(command_metadata_schema, command) or type(command.handler) ~= "function" then |
| 2930 return; | 2970 return; |
| 2931 end | 2971 end |
| 2932 host_command_info = { | 2972 host_command_info = { |
| 2933 [false] = { | 2973 [false] = { |
| 2934 host_selector = command.host_selector; | 2974 host_selector = command.host_selector; |
| 2935 handler = function (...) | 2975 handler = new_host_command_handler(qualified_name, command.host_selector, selector_index); |
| 2936 local selected_host = select(2, jid_split((select(selector_index, ...)))); | |
| 2937 if type(selected_host) ~= "string" then | |
| 2938 return nil, "Invalid or missing argument '"..command.host_selector.."'"; | |
| 2939 end | |
| 2940 if not prosody.hosts[selected_host] then | |
| 2941 return nil, "Unknown host: "..selected_host; | |
| 2942 end | |
| 2943 local host_handler = host_commands[qualified_name][selected_host]; | |
| 2944 if not host_handler then | |
| 2945 return nil, "This command is not available on "..selected_host; | |
| 2946 end | |
| 2947 return host_handler(...); | |
| 2948 end; | |
| 2949 }; | 2976 }; |
| 2950 }; | 2977 }; |
| 2951 host_commands[qualified_name] = host_command_info; | 2978 host_commands[qualified_name] = host_command_info; |
| 2952 end | 2979 end |
| 2953 if host_command_info[command_host] then | 2980 if host_command_info[command_host] then |
| 2954 module:log("warn", "Command %s() is already registered - overwriting with %s", qualified_name, mod_name); | 2981 module:log("warn", "Command %s() is already registered on %s - overwriting with %s", qualified_name, command_host, mod_name); |
| 2955 end | 2982 end |
| 2956 host_command_info[command_host] = handler; | 2983 host_command_info[command_host] = handler; |
| 2957 end | 2984 end |
| 2958 | 2985 |
| 2959 local section_t = def_env[command.section]; | 2986 local section_t = def_env[command.section]; |
| 3010 return; | 3037 return; |
| 3011 end | 3038 end |
| 3012 | 3039 |
| 3013 local section_t = def_env[command.section]; | 3040 local section_t = def_env[command.section]; |
| 3014 if not section_t or section_t[command.name] ~= handler then | 3041 if not section_t or section_t[command.name] ~= handler then |
| 3015 return; | 3042 -- Handler doesn't match, but it could be the host-selector wrapper |
| 3043 -- Let's try removing a per-host command | |
| 3044 local qualified_name = command.section..":"..command.name; | |
| 3045 local host_command_handlers = host_commands[qualified_name]; | |
| 3046 if host_command_handlers then | |
| 3047 -- Bingo! | |
| 3048 module:log("debug", "Removing command %s from %s", qualified_name, command_host); | |
| 3049 clear_host_commands(command_host, qualified_name); | |
| 3050 elseif section_t then | |
| 3051 module:log("warn", "Not removing shell command: handler mismatch: %q ~= %q", section_t and section_t[command.name], handler); | |
| 3052 return; | |
| 3053 end | |
| 3016 end | 3054 end |
| 3017 | 3055 |
| 3018 section_t[command.name] = nil; | 3056 section_t[command.name] = nil; |
| 3019 if next(section_t) == nil then -- Delete section if empty | 3057 if next(section_t) == nil then -- Delete section if empty |
| 3020 def_env[command.section] = nil; | 3058 def_env[command.section] = nil; |
| 3021 end | 3059 end |
| 3022 | |
| 3023 if command_host then | |
| 3024 local host_command_info = host_commands[command.section..":"..command.name]; | |
| 3025 if host_command_info then | |
| 3026 -- Remove our host handler | |
| 3027 host_command_info[command_host] = nil; | |
| 3028 -- Clean up entire command entry if there are no per-host handlers left | |
| 3029 local any_hosts = false; | |
| 3030 for k in pairs(host_command_info) do | |
| 3031 if k then -- metadata is false, ignore it | |
| 3032 any_hosts = true; | |
| 3033 break; | |
| 3034 end | |
| 3035 end | |
| 3036 if not any_hosts then | |
| 3037 host_commands[command.section..":"..command.name] = nil; | |
| 3038 end | |
| 3039 end | |
| 3040 end | |
| 3041 end | 3060 end |
| 3042 return on_command_added, on_command_removed; | 3061 return on_command_added, on_command_removed; |
| 3043 end | 3062 end |
| 3044 | 3063 |
| 3045 module:handle_items("shell-command", new_item_handlers()); | 3064 module:handle_items("shell-command", new_item_handlers()); |
| 3046 | 3065 |
| 3047 function module.add_host(host_module) | 3066 function module.add_host(host_module) |
| 3048 host_module:handle_items("shell-command", new_item_handlers(host_module.host)); | 3067 host_module:handle_items("shell-command", new_item_handlers(host_module.host)); |
| 3068 function host_module.unload() | |
| 3069 -- Due to non-deterministic unload order, we might not see item | |
| 3070 -- removal events for all commands before we get unloaded, so | |
| 3071 -- we clear everything from the host explicitly when we're | |
| 3072 -- unloaded (also sensible if we are unloaded manually) | |
| 3073 clear_host_commands(host_module.host); | |
| 3074 end | |
| 3049 end | 3075 end |
| 3050 | 3076 |
| 3051 function module.unload() | 3077 function module.unload() |
| 3052 stanza_watchers.cleanup(); | 3078 stanza_watchers.cleanup(); |
| 3053 end | 3079 end |
