Console: Make NavHelper non-static

add NavService interface
hang off ClientAppManager
i2psnark: register additional instances with NavService
This commit is contained in:
zzz
2022-10-19 15:33:53 -04:00
parent f83f467b28
commit 0224a0f03b
9 changed files with 116 additions and 19 deletions

View File

@ -29,6 +29,7 @@ import net.i2p.I2PAppContext;
import net.i2p.app.ClientApp; import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppManager; import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState; import net.i2p.app.ClientAppState;
import net.i2p.app.NavService;
import net.i2p.app.NotificationService; import net.i2p.app.NotificationService;
import net.i2p.client.I2PClient; import net.i2p.client.I2PClient;
import net.i2p.client.streaming.I2PSocketManager.DisconnectListener; import net.i2p.client.streaming.I2PSocketManager.DisconnectListener;
@ -291,12 +292,21 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
*/ */
public void start() { public void start() {
_running = true; _running = true;
ClientAppManager cmgr = _context.clientAppManager();
if ("i2psnark".equals(_contextName)) { if ("i2psnark".equals(_contextName)) {
// Register with the ClientAppManager so the rpc plugin can find us // Register with the ClientAppManager so the rpc plugin can find us
// only if default instance // only if default instance
ClientAppManager cmgr = _context.clientAppManager();
if (cmgr != null) if (cmgr != null)
cmgr.register(this); 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 = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
_monitor.start(); _monitor.start();
@ -377,11 +387,20 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
_connectionAcceptor.halt(); _connectionAcceptor.halt();
_idleChecker.cancel(); _idleChecker.cancel();
stopAllTorrents(true); stopAllTorrents(true);
ClientAppManager cmgr = _context.clientAppManager();
if ("i2psnark".equals(_contextName)) { if ("i2psnark".equals(_contextName)) {
// only if default instance // only if default instance
ClientAppManager cmgr = _context.clientAppManager();
if (cmgr != null) if (cmgr != null)
cmgr.unregister(this); 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()) if (_log.shouldWarn())
_log.warn("Snark stop() end"); _log.warn("Snark stop() end");

View File

@ -8,11 +8,15 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext; 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 // both indexed by standard (untranslated) app name
private static final Map<String, App> _apps = new ConcurrentHashMap<String, App>(4); private final Map<String, App> _apps = new ConcurrentHashMap<String, App>(4);
private static final Map<String, byte[]> _binary = new ConcurrentHashMap<String, byte[]>(4); private final Map<String, byte[]> _binary = new ConcurrentHashMap<String, byte[]>(4);
/** /**
* To register a new client application so that it shows up on the router * 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 * @param iconpath path-only URL starting with /, HTML escaped, or null
* @since 0.9.20 added iconpath parameter * @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("/")) if (iconpath != null && !iconpath.startsWith("/"))
iconpath = null; iconpath = null;
_apps.put(appName, new App(displayName, tooltip, path, iconpath)); _apps.put(appName, new App(displayName, tooltip, path, iconpath));
@ -36,7 +40,7 @@ public class NavHelper {
/** /**
* @param name standard name for the app * @param name standard name for the app
*/ */
public static void unregisterApp(String name) { public void unregisterApp(String name) {
_apps.remove(name); _apps.remove(name);
} }
@ -46,7 +50,7 @@ public class NavHelper {
* @return null if not found * @return null if not found
* @since 0.9.25 * @since 0.9.25
*/ */
public static byte[] getBinary(String name){ public byte[] getBinary(String name){
if(name != null) if(name != null)
return _binary.get(name); return _binary.get(name);
else else
@ -58,7 +62,7 @@ public class NavHelper {
* @param name plugin name * @param name plugin name
* @since 0.9.25 * @since 0.9.25
*/ */
public static void setBinary(String name, byte[] arr){ public void setBinary(String name, byte[] arr){
_binary.put(name, arr); _binary.put(name, arr);
} }
@ -67,7 +71,7 @@ public class NavHelper {
* Translated string is loaded by PluginStarter * Translated string is loaded by PluginStarter
* @return map of translated name to HTML string, or null if none * @return map of translated name to HTML string, or null if none
*/ */
public static Map<String, String> getClientAppLinks() { public Map<String, String> getClientAppLinks() {
if (_apps.isEmpty()) if (_apps.isEmpty())
return null; return null;
Map<String, String> rv = new HashMap<String, String>(_apps.size()); Map<String, String> rv = new HashMap<String, String>(_apps.size());
@ -97,7 +101,7 @@ public class NavHelper {
* @param name standard app name * @param name standard app name
* @since 0.9.45 * @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) { if (iconpath != null) {
buf.append("<img src=\"").append(iconpath).append("\" height=\"16\" width=\"16\" alt=\"\">"); buf.append("<img src=\"").append(iconpath).append("\" height=\"16\" width=\"16\" alt=\"\">");
} else if (name.equals("orchid")) { } else if (name.equals("orchid")) {
@ -115,7 +119,7 @@ public class NavHelper {
* @return non-null, possibly empty, unsorted * @return non-null, possibly empty, unsorted
* @since 0.9, public since 0.9.33, was package private * @since 0.9, public since 0.9.33, was package private
*/ */
public static List<App> getClientApps(I2PAppContext ctx) { public List<App> getClientApps(I2PAppContext ctx) {
if (_apps.isEmpty()) if (_apps.isEmpty())
return Collections.emptyList(); return Collections.emptyList();
List<App> rv = new ArrayList<App>(_apps.size()); List<App> rv = new ArrayList<App>(_apps.size());
@ -140,4 +144,45 @@ public class NavHelper {
} }
return rv; 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
} }

View File

@ -434,7 +434,7 @@ public class PluginStarter implements Runnable {
if(fullprop != null && fullprop.length() > 1){ if(fullprop != null && fullprop.length() > 1){
byte[] decoded = Base64.decode(fullprop); byte[] decoded = Base64.decode(fullprop);
if(decoded != null) { if(decoded != null) {
NavHelper.setBinary(appName, decoded); NavHelper.getInstance(ctx).setBinary(appName, decoded);
iconfile = "/Plugins/pluginicon?plugin=" + appName; iconfile = "/Plugins/pluginicon?plugin=" + appName;
} else { } else {
iconfile = "/themes/console/images/plugin.png"; iconfile = "/themes/console/images/plugin.png";
@ -546,7 +546,7 @@ public class PluginStarter implements Runnable {
String tip = stripHTML(props, "consoleLinkTooltip_" + Messages.getLanguage(ctx)); String tip = stripHTML(props, "consoleLinkTooltip_" + Messages.getLanguage(ctx));
if (tip == null) if (tip == null)
tip = stripHTML(props, "consoleLinkTooltip"); tip = stripHTML(props, "consoleLinkTooltip");
NavHelper.registerApp(appName, name, url, tip, iconfile); NavHelper.getInstance(ctx).registerApp(appName, name, url, tip, iconfile);
} }
return true; return true;
@ -627,7 +627,7 @@ public class PluginStarter implements Runnable {
//} //}
// remove summary bar link // remove summary bar link
NavHelper.unregisterApp(appName); NavHelper.getInstance(ctx).unregisterApp(appName);
return true; return true;
} }

View File

@ -101,6 +101,7 @@ public class RouterConsoleRunner implements RouterApp {
private final RouterContext _context; private final RouterContext _context;
private final ClientAppManager _mgr; private final ClientAppManager _mgr;
private final NavHelper _navHelper;
private volatile ClientAppState _state = UNINITIALIZED; private volatile ClientAppState _state = UNINITIALIZED;
private Server _server; private Server _server;
private static ScheduledExecutorScheduler _jettyTimer; private static ScheduledExecutorScheduler _jettyTimer;
@ -179,6 +180,7 @@ public class RouterConsoleRunner implements RouterApp {
public RouterConsoleRunner(RouterContext ctx, ClientAppManager mgr, String args[]) { public RouterConsoleRunner(RouterContext ctx, ClientAppManager mgr, String args[]) {
_context = ctx; _context = ctx;
_mgr = mgr; _mgr = mgr;
_navHelper = new NavHelper();
if (args.length == 0) { if (args.length == 0) {
// _listenHost and _webAppsDir are defaulted below // _listenHost and _webAppsDir are defaulted below
_listenPort = Integer.toString(DEFAULT_LISTEN_PORT); _listenPort = Integer.toString(DEFAULT_LISTEN_PORT);
@ -248,6 +250,7 @@ public class RouterConsoleRunner implements RouterApp {
try { try {
_server.stop(); _server.stop();
} catch (Exception ie) {} } catch (Exception ie) {}
_mgr.unregister(_navHelper);
PortMapper portMapper = _context.portMapper(); PortMapper portMapper = _context.portMapper();
portMapper.unregister(PortMapper.SVC_CONSOLE); portMapper.unregister(PortMapper.SVC_CONSOLE);
portMapper.unregister(PortMapper.SVC_HTTPS_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 // This also prevents one webapp from breaking the whole thing
List<String> notStarted = new ArrayList<String>(); List<String> notStarted = new ArrayList<String>();
if (_server.isRunning()) { if (_server.isRunning()) {
if (_mgr != null)
_mgr.register(_navHelper);
File dir = new File(_webAppsDir); File dir = new File(_webAppsDir);
File files[] = dir.listFiles(WAR_FILTER); File files[] = dir.listFiles(WAR_FILTER);
if (files != null) { if (files != null) {

View File

@ -15,7 +15,6 @@ import net.i2p.router.web.CSSHelper;
import net.i2p.router.web.FormHandler; import net.i2p.router.web.FormHandler;
import static net.i2p.router.web.GraphConstants.*; import static net.i2p.router.web.GraphConstants.*;
import net.i2p.router.web.HelperBase; import net.i2p.router.web.HelperBase;
import net.i2p.router.web.NavHelper;
import net.i2p.router.web.StatSummarizer; import net.i2p.router.web.StatSummarizer;
import net.i2p.router.web.SummaryListener; import net.i2p.router.web.SummaryListener;
import net.i2p.stat.Rate; import net.i2p.stat.Rate;

View File

@ -140,7 +140,7 @@ public class HomeHelper extends HelperBase {
/** @since 0.9.47 */ /** @since 0.9.47 */
public String getPlugins() { public String getPlugins() {
List<App> plugins = NavHelper.getClientApps(_context); List<App> plugins = NavHelper.getInstance(_context).getClientApps(_context);
String table = pluginTable(plugins); String table = pluginTable(plugins);
if (table.length() == 0) { if (table.length() == 0) {
return ""; return "";

View File

@ -278,7 +278,7 @@ class SummaryBarRenderer {
} }
} }
Map<String, String> apps = NavHelper.getClientAppLinks(); Map<String, String> apps = NavHelper.getInstance(_context).getClientAppLinks();
if (apps != null) if (apps != null)
svcs.putAll(apps); svcs.putAll(apps);
if (!svcs.isEmpty()) { if (!svcs.isEmpty()) {

View File

@ -37,7 +37,7 @@ public class CodedIconRendererServlet extends HttpServlet {
protected void doGet(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException { protected void doGet(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException {
byte[] data; byte[] data;
String name = srq.getParameter("plugin"); String name = srq.getParameter("plugin");
data = NavHelper.getBinary(name); data = NavHelper.getInstance().getBinary(name);
//set as many headers as are common to any outcome //set as many headers as are common to any outcome

View File

@ -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);
}