From 0224a0f03b7d374634ea264b9b67caec32cd6a4c Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 19 Oct 2022 15:33:53 -0400 Subject: [PATCH] Console: Make NavHelper non-static add NavService interface hang off ClientAppManager i2psnark: register additional instances with NavService --- .../src/org/klomp/snark/SnarkManager.java | 23 ++++++- .../src/net/i2p/router/web/NavHelper.java | 65 ++++++++++++++++--- .../src/net/i2p/router/web/PluginStarter.java | 6 +- .../i2p/router/web/RouterConsoleRunner.java | 5 ++ .../i2p/router/web/helpers/GraphHelper.java | 1 - .../i2p/router/web/helpers/HomeHelper.java | 2 +- .../web/helpers/SummaryBarRenderer.java | 2 +- .../servlets/CodedIconRendererServlet.java | 2 +- core/java/src/net/i2p/app/NavService.java | 29 +++++++++ 9 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 core/java/src/net/i2p/app/NavService.java diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 57d50c20f..7c26eee66 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -29,6 +29,7 @@ import net.i2p.I2PAppContext; import net.i2p.app.ClientApp; import net.i2p.app.ClientAppManager; import net.i2p.app.ClientAppState; +import net.i2p.app.NavService; import net.i2p.app.NotificationService; import net.i2p.client.I2PClient; import net.i2p.client.streaming.I2PSocketManager.DisconnectListener; @@ -291,12 +292,21 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList */ public void start() { _running = true; + ClientAppManager cmgr = _context.clientAppManager(); if ("i2psnark".equals(_contextName)) { // Register with the ClientAppManager so the rpc plugin can find us // only if default instance - ClientAppManager cmgr = _context.clientAppManager(); if (cmgr != null) cmgr.register(this); + } else { + // Register link with NavHelper + if (cmgr != null) { + NavService nav = (NavService) cmgr.getRegisteredApp("NavHelper"); + if (nav != null) { + String name = DataHelper.stripHTML(_contextPath.substring(1)); + nav.registerApp(name, name, _contextPath, null, "/themes/console/images/i2psnark.png"); + } + } } _monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true); _monitor.start(); @@ -377,11 +387,20 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList _connectionAcceptor.halt(); _idleChecker.cancel(); stopAllTorrents(true); + ClientAppManager cmgr = _context.clientAppManager(); if ("i2psnark".equals(_contextName)) { // only if default instance - ClientAppManager cmgr = _context.clientAppManager(); if (cmgr != null) cmgr.unregister(this); + } else { + // Unregister link with NavHelper + if (cmgr != null) { + NavService nav = (NavService) cmgr.getRegisteredApp("NavHelper"); + if (nav != null) { + String name = DataHelper.stripHTML(_contextPath.substring(1)); + nav.unregisterApp(name); + } + } } if (_log.shouldWarn()) _log.warn("Snark stop() end"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java index fb0a9a32a..6ad6e1610 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java @@ -8,11 +8,15 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import net.i2p.I2PAppContext; +import net.i2p.app.ClientApp; +import net.i2p.app.ClientAppManager; +import net.i2p.app.ClientAppState; +import net.i2p.app.NavService; -public class NavHelper { +public class NavHelper implements NavService, ClientApp { // both indexed by standard (untranslated) app name - private static final Map _apps = new ConcurrentHashMap(4); - private static final Map _binary = new ConcurrentHashMap(4); + private final Map _apps = new ConcurrentHashMap(4); + private final Map _binary = new ConcurrentHashMap(4); /** * To register a new client application so that it shows up on the router @@ -27,7 +31,7 @@ public class NavHelper { * @param iconpath path-only URL starting with /, HTML escaped, or null * @since 0.9.20 added iconpath parameter */ - public static void registerApp(String appName, String displayName, String path, String tooltip, String iconpath) { + public void registerApp(String appName, String displayName, String path, String tooltip, String iconpath) { if (iconpath != null && !iconpath.startsWith("/")) iconpath = null; _apps.put(appName, new App(displayName, tooltip, path, iconpath)); @@ -36,7 +40,7 @@ public class NavHelper { /** * @param name standard name for the app */ - public static void unregisterApp(String name) { + public void unregisterApp(String name) { _apps.remove(name); } @@ -46,7 +50,7 @@ public class NavHelper { * @return null if not found * @since 0.9.25 */ - public static byte[] getBinary(String name){ + public byte[] getBinary(String name){ if(name != null) return _binary.get(name); else @@ -58,7 +62,7 @@ public class NavHelper { * @param name plugin name * @since 0.9.25 */ - public static void setBinary(String name, byte[] arr){ + public void setBinary(String name, byte[] arr){ _binary.put(name, arr); } @@ -67,7 +71,7 @@ public class NavHelper { * Translated string is loaded by PluginStarter * @return map of translated name to HTML string, or null if none */ - public static Map getClientAppLinks() { + public Map getClientAppLinks() { if (_apps.isEmpty()) return null; Map rv = new HashMap(_apps.size()); @@ -97,7 +101,7 @@ public class NavHelper { * @param name standard app name * @since 0.9.45 */ - private static void getClientAppImg(StringBuilder buf, String name, String iconpath) { + private void getClientAppImg(StringBuilder buf, String name, String iconpath) { if (iconpath != null) { buf.append("\"\""); } else if (name.equals("orchid")) { @@ -115,7 +119,7 @@ public class NavHelper { * @return non-null, possibly empty, unsorted * @since 0.9, public since 0.9.33, was package private */ - public static List getClientApps(I2PAppContext ctx) { + public List getClientApps(I2PAppContext ctx) { if (_apps.isEmpty()) return Collections.emptyList(); List rv = new ArrayList(_apps.size()); @@ -140,4 +144,45 @@ public class NavHelper { } return rv; } + + /** @since 0.9.56 */ + public static NavHelper getInstance() { + return getInstance(I2PAppContext.getGlobalContext()); + } + + /** @since 0.9.56 */ + public static NavHelper getInstance(I2PAppContext ctx) { + ClientAppManager cmgr = ctx.clientAppManager(); + if (cmgr != null) + return (NavHelper) cmgr.getRegisteredApp("NavHelper"); + return null; + } + + /////// ClientApp methods + + /** @since 0.9.56 */ + public void startup() {} + + /** @since 0.9.56 */ + public void shutdown(String[] args) { + _apps.clear(); + _binary.clear(); + } + + /** @since 0.9.56 */ + public ClientAppState getState() { + return ClientAppState.RUNNING; + } + + /** @since 0.9.56 */ + public String getName() { + return "NavHelper"; + } + + /** @since 0.9.56 */ + public String getDisplayName() { + return "Nav Helper"; + } + + /////// end ClientApp methods } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java index a6f0d9823..be757988e 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java @@ -434,7 +434,7 @@ public class PluginStarter implements Runnable { if(fullprop != null && fullprop.length() > 1){ byte[] decoded = Base64.decode(fullprop); if(decoded != null) { - NavHelper.setBinary(appName, decoded); + NavHelper.getInstance(ctx).setBinary(appName, decoded); iconfile = "/Plugins/pluginicon?plugin=" + appName; } else { iconfile = "/themes/console/images/plugin.png"; @@ -546,7 +546,7 @@ public class PluginStarter implements Runnable { String tip = stripHTML(props, "consoleLinkTooltip_" + Messages.getLanguage(ctx)); if (tip == null) tip = stripHTML(props, "consoleLinkTooltip"); - NavHelper.registerApp(appName, name, url, tip, iconfile); + NavHelper.getInstance(ctx).registerApp(appName, name, url, tip, iconfile); } return true; @@ -627,7 +627,7 @@ public class PluginStarter implements Runnable { //} // remove summary bar link - NavHelper.unregisterApp(appName); + NavHelper.getInstance(ctx).unregisterApp(appName); return true; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index eddae60e2..533b18fab 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -101,6 +101,7 @@ public class RouterConsoleRunner implements RouterApp { private final RouterContext _context; private final ClientAppManager _mgr; + private final NavHelper _navHelper; private volatile ClientAppState _state = UNINITIALIZED; private Server _server; private static ScheduledExecutorScheduler _jettyTimer; @@ -179,6 +180,7 @@ public class RouterConsoleRunner implements RouterApp { public RouterConsoleRunner(RouterContext ctx, ClientAppManager mgr, String args[]) { _context = ctx; _mgr = mgr; + _navHelper = new NavHelper(); if (args.length == 0) { // _listenHost and _webAppsDir are defaulted below _listenPort = Integer.toString(DEFAULT_LISTEN_PORT); @@ -248,6 +250,7 @@ public class RouterConsoleRunner implements RouterApp { try { _server.stop(); } catch (Exception ie) {} + _mgr.unregister(_navHelper); PortMapper portMapper = _context.portMapper(); portMapper.unregister(PortMapper.SVC_CONSOLE); portMapper.unregister(PortMapper.SVC_HTTPS_CONSOLE); @@ -814,6 +817,8 @@ public class RouterConsoleRunner implements RouterApp { // This also prevents one webapp from breaking the whole thing List notStarted = new ArrayList(); if (_server.isRunning()) { + if (_mgr != null) + _mgr.register(_navHelper); File dir = new File(_webAppsDir); File files[] = dir.listFiles(WAR_FILTER); if (files != null) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/GraphHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/GraphHelper.java index 9a81a498a..c9c18facb 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/GraphHelper.java @@ -15,7 +15,6 @@ import net.i2p.router.web.CSSHelper; import net.i2p.router.web.FormHandler; import static net.i2p.router.web.GraphConstants.*; import net.i2p.router.web.HelperBase; -import net.i2p.router.web.NavHelper; import net.i2p.router.web.StatSummarizer; import net.i2p.router.web.SummaryListener; import net.i2p.stat.Rate; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/HomeHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/HomeHelper.java index a8661176d..1e83e80ae 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/HomeHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/HomeHelper.java @@ -140,7 +140,7 @@ public class HomeHelper extends HelperBase { /** @since 0.9.47 */ public String getPlugins() { - List plugins = NavHelper.getClientApps(_context); + List plugins = NavHelper.getInstance(_context).getClientApps(_context); String table = pluginTable(plugins); if (table.length() == 0) { return ""; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java index 42a5ca898..0ce2f3627 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/helpers/SummaryBarRenderer.java @@ -278,7 +278,7 @@ class SummaryBarRenderer { } } - Map apps = NavHelper.getClientAppLinks(); + Map apps = NavHelper.getInstance(_context).getClientAppLinks(); if (apps != null) svcs.putAll(apps); if (!svcs.isEmpty()) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/servlets/CodedIconRendererServlet.java b/apps/routerconsole/java/src/net/i2p/router/web/servlets/CodedIconRendererServlet.java index d90bd7b45..81a3fa223 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/servlets/CodedIconRendererServlet.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/servlets/CodedIconRendererServlet.java @@ -37,7 +37,7 @@ public class CodedIconRendererServlet extends HttpServlet { protected void doGet(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException { byte[] data; String name = srq.getParameter("plugin"); - data = NavHelper.getBinary(name); + data = NavHelper.getInstance().getBinary(name); //set as many headers as are common to any outcome diff --git a/core/java/src/net/i2p/app/NavService.java b/core/java/src/net/i2p/app/NavService.java new file mode 100644 index 000000000..8a87328f1 --- /dev/null +++ b/core/java/src/net/i2p/app/NavService.java @@ -0,0 +1,29 @@ +package net.i2p.app; + +/** + * Service to put links on the console. + * Here so webapps can use it without dependency on console. + * + * @since 0.9.56 adapted from console NavHelper + */ +public interface NavService { + + /** + * To register a new client application so that it shows up on the router + * console's nav bar, it should be registered with this singleton. + * + * @param appName standard name for the app (plugin) + * @param displayName translated name the app will be called in the link + * warning, this is the display name aka ConsoleLinkName, not the plugin name + * @param path full path pointing to the application's root + * (e.g. /i2ptunnel/index.jsp), non-null + * @param tooltip HTML escaped text or null + * @param iconpath path-only URL starting with /, HTML escaped, or null + */ + public void registerApp(String appName, String displayName, String path, String tooltip, String iconpath); + + /** + * @param name standard name for the app + */ + public void unregisterApp(String name); +}