pluginhost: rework run_hooks() to be shorter, add callback variant; implement exception handling for both

This commit is contained in:
Andrew Dolgov 2021-02-08 14:24:45 +03:00
parent 20b56b5b23
commit 1eb1629d9e
11 changed files with 115 additions and 91 deletions

View File

@ -490,17 +490,17 @@ class Handler_Public extends Handler {
} }
function updateTask() { function updateTask() {
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false); PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK);
} }
function housekeepingTask() { function housekeepingTask() {
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", false); PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING);
} }
function globalUpdateFeeds() { function globalUpdateFeeds() {
RPC::updaterandomfeed_real(); RPC::updaterandomfeed_real();
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", false); PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK);
} }
function sharepopup() { function sharepopup() {

View File

@ -22,54 +22,54 @@ class PluginHost {
// Hooks marked with *1 are run in global context and available // Hooks marked with *1 are run in global context and available
// to plugins loaded in config.php only // to plugins loaded in config.php only
const HOOK_ARTICLE_BUTTON = 1; const HOOK_ARTICLE_BUTTON = "hook_article_button";
const HOOK_ARTICLE_FILTER = 2; const HOOK_ARTICLE_FILTER = "hook_article_filter";
const HOOK_PREFS_TAB = 3; const HOOK_PREFS_TAB = "hook_prefs_tab";
const HOOK_PREFS_TAB_SECTION = 4; const HOOK_PREFS_TAB_SECTION = "hook_prefs_tab_section";
const HOOK_PREFS_TABS = 5; const HOOK_PREFS_TABS = "hook_prefs_tabs";
const HOOK_FEED_PARSED = 6; const HOOK_FEED_PARSED = "hook_feed_parsed";
const HOOK_UPDATE_TASK = 7; // *1 const HOOK_UPDATE_TASK = "hook_update_task"; //*1
const HOOK_AUTH_USER = 8; const HOOK_AUTH_USER = "hook_auth_user";
const HOOK_HOTKEY_MAP = 9; const HOOK_HOTKEY_MAP = "hook_hotkey_map";
const HOOK_RENDER_ARTICLE = 10; const HOOK_RENDER_ARTICLE = "hook_render_article";
const HOOK_RENDER_ARTICLE_CDM = 11; const HOOK_RENDER_ARTICLE_CDM = "hook_render_article_cdm";
const HOOK_FEED_FETCHED = 12; const HOOK_FEED_FETCHED = "hook_feed_fetched";
const HOOK_SANITIZE = 13; const HOOK_SANITIZE = "hook_sanitize";
const HOOK_RENDER_ARTICLE_API = 14; const HOOK_RENDER_ARTICLE_API = "hook_render_article_api";
const HOOK_TOOLBAR_BUTTON = 15; const HOOK_TOOLBAR_BUTTON = "hook_toolbar_button";
const HOOK_ACTION_ITEM = 16; const HOOK_ACTION_ITEM = "hook_action_item";
const HOOK_HEADLINE_TOOLBAR_BUTTON = 17; const HOOK_HEADLINE_TOOLBAR_BUTTON = "hook_headline_toolbar_button";
const HOOK_HOTKEY_INFO = 18; const HOOK_HOTKEY_INFO = "hook_hotkey_info";
const HOOK_ARTICLE_LEFT_BUTTON = 19; const HOOK_ARTICLE_LEFT_BUTTON = "hook_article_left_button";
const HOOK_PREFS_EDIT_FEED = 20; const HOOK_PREFS_EDIT_FEED = "hook_prefs_edit_feed";
const HOOK_PREFS_SAVE_FEED = 21; const HOOK_PREFS_SAVE_FEED = "hook_prefs_save_feed";
const HOOK_FETCH_FEED = 22; const HOOK_FETCH_FEED = "hook_fetch_feed";
const HOOK_QUERY_HEADLINES = 23; const HOOK_QUERY_HEADLINES = "hook_query_headlines";
const HOOK_HOUSE_KEEPING = 24; // *1 const HOOK_HOUSE_KEEPING = "hook_house_keeping"; //*1
const HOOK_SEARCH = 25; const HOOK_SEARCH = "hook_search";
const HOOK_FORMAT_ENCLOSURES = 26; const HOOK_FORMAT_ENCLOSURES = "hook_format_enclosures";
const HOOK_SUBSCRIBE_FEED = 27; const HOOK_SUBSCRIBE_FEED = "hook_subscribe_feed";
const HOOK_HEADLINES_BEFORE = 28; const HOOK_HEADLINES_BEFORE = "hook_headlines_before";
const HOOK_RENDER_ENCLOSURE = 29; const HOOK_RENDER_ENCLOSURE = "hook_render_enclosure";
const HOOK_ARTICLE_FILTER_ACTION = 30; const HOOK_ARTICLE_FILTER_ACTION = "hook_article_filter_action";
const HOOK_ARTICLE_EXPORT_FEED = 31; const HOOK_ARTICLE_EXPORT_FEED = "hook_article_export_feed";
const HOOK_MAIN_TOOLBAR_BUTTON = 32; const HOOK_MAIN_TOOLBAR_BUTTON = "hook_main_toolbar_button";
const HOOK_ENCLOSURE_ENTRY = 33; const HOOK_ENCLOSURE_ENTRY = "hook_enclosure_entry";
const HOOK_FORMAT_ARTICLE = 34; const HOOK_FORMAT_ARTICLE = "hook_format_article";
const HOOK_FORMAT_ARTICLE_CDM = 35; /* RIP */ const HOOK_FORMAT_ARTICLE_CDM = "hook_format_article_cdm"; /* RIP */
const HOOK_FEED_BASIC_INFO = 36; const HOOK_FEED_BASIC_INFO = "hook_feed_basic_info";
const HOOK_SEND_LOCAL_FILE = 37; const HOOK_SEND_LOCAL_FILE = "hook_send_local_file";
const HOOK_UNSUBSCRIBE_FEED = 38; const HOOK_UNSUBSCRIBE_FEED = "hook_unsubscribe_feed";
const HOOK_SEND_MAIL = 39; const HOOK_SEND_MAIL = "hook_send_mail";
const HOOK_FILTER_TRIGGERED = 40; const HOOK_FILTER_TRIGGERED = "hook_filter_triggered";
const HOOK_GET_FULL_TEXT = 41; const HOOK_GET_FULL_TEXT = "hook_get_full_text";
const HOOK_ARTICLE_IMAGE = 42; const HOOK_ARTICLE_IMAGE = "hook_article_image";
const HOOK_FEED_TREE = 43; const HOOK_FEED_TREE = "hook_feed_tree";
const HOOK_IFRAME_WHITELISTED = 44; const HOOK_IFRAME_WHITELISTED = "hook_iframe_whitelisted";
const HOOK_ENCLOSURE_IMPORTED = 45; const HOOK_ENCLOSURE_IMPORTED = "hook_enclosure_imported";
const HOOK_HEADLINES_CUSTOM_SORT_MAP = 46; const HOOK_HEADLINES_CUSTOM_SORT_MAP = "hook_headlines_custom_sort_map";
const HOOK_HEADLINES_CUSTOM_SORT_OVERRIDE = 47; const HOOK_HEADLINES_CUSTOM_SORT_OVERRIDE = "hook_headlines_custom_sort_override";
const HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM = 48; const HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM = "hook_headline_toolbar_select_menu_item";
const KIND_ALL = 1; const KIND_ALL = 1;
const KIND_SYSTEM = 2; const KIND_SYSTEM = 2;
@ -131,9 +131,35 @@ class PluginHost {
return $this->plugins[strtolower($name)] ?? null; return $this->plugins[strtolower($name)] ?? null;
} }
function run_hooks($type, $method, $args) { function run_hooks($hook, ...$args) {
foreach ($this->get_hooks($type) as $hook) { $method = strtolower($hook);
$hook->$method($args);
foreach ($this->get_hooks($hook) as $plugin) {
Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
try {
$plugin->$method(...$args);
} catch (Exception $ex) {
user_error($ex, E_USER_WARNING);
} catch (Error $err) {
user_error($err, E_USER_WARNING);
}
}
}
function run_hooks_callback($hook, $callback, ...$args) {
$method = strtolower($hook);
foreach ($this->get_hooks($hook) as $plugin) {
//Debug::log("invoking: " . get_class($plugin) . "->$hook()", Debug::$LOG_VERBOSE);
try {
$callback($plugin->$method(...$args), $plugin);
} catch (Exception $ex) {
user_error($ex, E_USER_WARNING);
} catch (Error $err) {
user_error($err, E_USER_WARNING);
}
} }
} }

View File

@ -800,8 +800,7 @@ class Pref_Feeds extends Handler_Protected {
print '</div><div dojoType="dijit.layout.ContentPane" title="'.__('Plugins').'">'; print '</div><div dojoType="dijit.layout.ContentPane" title="'.__('Plugins').'">';
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_EDIT_FEED, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_EDIT_FEED, $feed_id);
"hook_prefs_edit_feed", $feed_id);
print "</div></div>"; print "</div></div>";
@ -1072,8 +1071,7 @@ class Pref_Feeds extends Handler_Protected {
RSSUtils::set_basic_feed_info($feed_id); RSSUtils::set_basic_feed_info($feed_id);
} */ } */
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_SAVE_FEED, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_SAVE_FEED, $feed_id);
"hook_prefs_save_feed", $feed_id);
} else { } else {
$feed_data = array(); $feed_data = array();
@ -1384,8 +1382,7 @@ class Pref_Feeds extends Handler_Protected {
print "<button dojoType='dijit.form.Button' class='alt-primary' onclick=\"return App.displayDlg('".__("Public OPML URL")."','pubOPMLUrl')\">". print "<button dojoType='dijit.form.Button' class='alt-primary' onclick=\"return App.displayDlg('".__("Public OPML URL")."','pubOPMLUrl')\">".
__('Display published OPML URL')."</button> "; __('Display published OPML URL')."</button> ";
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsOPML");
"hook_prefs_tab_section", "prefFeedsOPML");
print "</div>"; # pane print "</div>"; # pane
@ -1403,13 +1400,11 @@ class Pref_Feeds extends Handler_Protected {
print "<button class=\"alt-danger\" dojoType=\"dijit.form.Button\" onclick=\"return Helpers.clearFeedAccessKeys()\">". print "<button class=\"alt-danger\" dojoType=\"dijit.form.Button\" onclick=\"return Helpers.clearFeedAccessKeys()\">".
__('Clear all generated URLs')."</button> "; __('Clear all generated URLs')."</button> ";
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefFeedsPublishedGenerated");
"hook_prefs_tab_section", "prefFeedsPublishedGenerated");
print "</div>"; #pane print "</div>"; #pane
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFeeds");
"hook_prefs_tab", "prefFeeds");
print "</div>"; #container print "</div>"; #container
} }

View File

@ -814,8 +814,7 @@ class Pref_Filters extends Handler_Protected {
print "</div>"; #pane print "</div>"; #pane
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefFilters");
"hook_prefs_tab", "prefFilters");
print "</div>"; #container print "</div>"; #container

View File

@ -304,8 +304,7 @@ class Pref_Labels extends Handler_Protected {
print "</div>"; #pane print "</div>"; #pane
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefLabels");
"hook_prefs_tab", "prefLabels");
print "</div>"; #container print "</div>"; #container

View File

@ -559,8 +559,7 @@ class Pref_Prefs extends Handler_Protected {
print "</div>"; # tab container print "</div>"; # tab container
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsAuth");
"hook_prefs_tab_section", "prefPrefsAuth");
print "</div>"; #pane print "</div>"; #pane
@ -814,8 +813,7 @@ class Pref_Prefs extends Handler_Protected {
print_hidden("boolean_prefs", "$listed_boolean_prefs"); print_hidden("boolean_prefs", "$listed_boolean_prefs");
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsPrefsInside");
"hook_prefs_tab_section", "prefPrefsPrefsInside");
print '</div>'; # inside pane print '</div>'; # inside pane
print '<div dojoType="dijit.layout.ContentPane" region="bottom">'; print '<div dojoType="dijit.layout.ContentPane" region="bottom">';
@ -840,8 +838,7 @@ class Pref_Prefs extends Handler_Protected {
print "&nbsp;"; print "&nbsp;";
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefPrefsPrefsOutside");
"hook_prefs_tab_section", "prefPrefsPrefsOutside");
print "</form>"; print "</form>";
print '</div>'; # inner pane print '</div>'; # inner pane
@ -1005,8 +1002,7 @@ class Pref_Prefs extends Handler_Protected {
print "</form>"; print "</form>";
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefPrefs");
"hook_prefs_tab", "prefPrefs");
print "</div>"; #container print "</div>"; #container

View File

@ -176,8 +176,7 @@ class Pref_System extends Handler_Protected {
print "</div>"; # accordion pane print "</div>"; # accordion pane
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefSystem");
"hook_prefs_tab", "prefSystem");
print "</div>"; #container print "</div>"; #container
} }

View File

@ -355,8 +355,7 @@ class Pref_Users extends Handler_Protected {
<button dojoType='dijit.form.Button' onclick='Users.resetSelected()'>". <button dojoType='dijit.form.Button' onclick='Users.resetSelected()'>".
__('Reset password')."</button dojoType=\"dijit.form.Button\">"; __('Reset password')."</button dojoType=\"dijit.form.Button\">";
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB_SECTION, "prefUsersToolbar");
"hook_prefs_tab_section", "prefUsersToolbar");
print "</div>"; #toolbar print "</div>"; #toolbar
print "</div>"; #pane print "</div>"; #pane
@ -429,8 +428,7 @@ class Pref_Users extends Handler_Protected {
print "</div>"; #pane print "</div>"; #pane
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TAB, "prefUsers");
"hook_prefs_tab", "prefUsers");
print "</div>"; #container print "</div>"; #container

View File

@ -808,7 +808,20 @@ class RSSUtils {
Debug::log("hash differs, applying plugin filters:", Debug::$LOG_VERBOSE); Debug::log("hash differs, applying plugin filters:", Debug::$LOG_VERBOSE);
foreach ($pluginhost->get_hooks(PluginHost::HOOK_ARTICLE_FILTER) as $plugin) { $start_ts = microtime(true);
PluginHost::getInstance()->run_hooks_callback(PluginHost::HOOK_ARTICLE_FILTER,
function ($result, $plugin) use (&$article, &$entry_plugin_data, $start_ts) {
$article = $result;
$entry_plugin_data .= mb_strtolower(get_class($plugin)) . ",";
Debug::log(sprintf("=== %.4f (sec) %s", microtime(true) - $start_ts, get_class($plugin)),
Debug::$LOG_VERBOSE);
},
$article);
/* foreach ($pluginhost->get_hooks(PluginHost::HOOK_ARTICLE_FILTER) as $plugin) {
Debug::log("... " . get_class($plugin), Debug::$LOG_VERBOSE); Debug::log("... " . get_class($plugin), Debug::$LOG_VERBOSE);
$start = microtime(true); $start = microtime(true);
@ -817,7 +830,7 @@ class RSSUtils {
Debug::log(sprintf("=== %.4f (sec)", microtime(true) - $start), Debug::$LOG_VERBOSE); Debug::log(sprintf("=== %.4f (sec)", microtime(true) - $start), Debug::$LOG_VERBOSE);
$entry_plugin_data .= mb_strtolower(get_class($plugin)) . ","; $entry_plugin_data .= mb_strtolower(get_class($plugin)) . ",";
} } */
if (Debug::get_loglevel() >= 3) { if (Debug::get_loglevel() >= 3) {
print "processed content: "; print "processed content: ";
@ -1619,7 +1632,7 @@ class RSSUtils {
UserHelper::load_user_plugins($owner_uid, $tmph); UserHelper::load_user_plugins($owner_uid, $tmph);
$tmph->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", ""); $tmph->run_hooks(PluginHost::HOOK_HOUSE_KEEPING);
} }
static function housekeeping_common() { static function housekeeping_common() {
@ -1635,7 +1648,7 @@ class RSSUtils {
Article::purge_orphans(); Article::purge_orphans();
self::cleanup_counters_cache(); self::cleanup_counters_cache();
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING, "hook_house_keeping", ""); PluginHost::getInstance()->run_hooks(PluginHost::HOOK_HOUSE_KEEPING);
} }
static function check_feed_favicon($site_url, $feed) { static function check_feed_favicon($site_url, $feed) {

View File

@ -160,8 +160,7 @@
title="<i class='material-icons'>info_outline</i> <?php echo __('System') ?>"></div> title="<i class='material-icons'>info_outline</i> <?php echo __('System') ?>"></div>
<?php } ?> <?php } ?>
<?php <?php
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TABS, PluginHost::getInstance()->run_hooks(PluginHost::HOOK_PREFS_TABS);
"hook_prefs_tabs", false);
?> ?>
</div> </div>
<?php $version = get_version($git_commit, $git_timestamp, $last_error); ?> <?php $version = get_version($git_commit, $git_timestamp, $last_error); ?>

View File

@ -216,7 +216,7 @@
RSSUtils::update_daemon_common(DAEMON_FEED_LIMIT, $options); RSSUtils::update_daemon_common(DAEMON_FEED_LIMIT, $options);
RSSUtils::housekeeping_common(); RSSUtils::housekeeping_common();
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $options); PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, $options);
} }
if (isset($options["daemon"])) { if (isset($options["daemon"])) {
@ -261,7 +261,7 @@
if (!isset($options["pidlock"]) || $options["task"] == 0) if (!isset($options["pidlock"]) || $options["task"] == 0)
RSSUtils::housekeeping_common(); RSSUtils::housekeeping_common();
PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, "hook_update_task", $options); PluginHost::getInstance()->run_hooks(PluginHost::HOOK_UPDATE_TASK, $options);
} }
if (isset($options["cleanup-tags"])) { if (isset($options["cleanup-tags"])) {