* Plugins:

- Hook up update/delete/check/save buttons
      - Implement delete
      - Hide unless router.enablePlugins=true
This commit is contained in:
zzz
2010-02-10 19:09:35 +00:00
parent cfc49ab261
commit 949aea951e
7 changed files with 136 additions and 20 deletions

View File

@ -35,6 +35,10 @@ public class ConfigClientsHandler extends FormHandler {
saveWebAppChanges(); saveWebAppChanges();
return; return;
} }
if (_action.equals(_("Save Plugin Configuration"))) {
savePluginChanges();
return;
}
if (_action.equals(_("Install Plugin"))) { if (_action.equals(_("Install Plugin"))) {
installPlugin(); installPlugin();
return; return;
@ -60,10 +64,42 @@ public class ConfigClientsHandler extends FormHandler {
try { try {
appnum = Integer.parseInt(app); appnum = Integer.parseInt(app);
} catch (NumberFormatException nfe) {} } catch (NumberFormatException nfe) {}
if (appnum >= 0) if (appnum >= 0) {
deleteClient(appnum); deleteClient(appnum);
} else {
try {
PluginStarter.stopPlugin(_context, app);
} catch (Exception e) {}
PluginStarter.deletePlugin(_context, app);
addFormNotice(_("Deleted plugin {0}", app));
}
return; return;
} }
// value
if (_action.startsWith("Stop ")) {
String app = _action.substring(5);
try {
PluginStarter.stopPlugin(_context, app);
} catch (Exception e) {}
addFormNotice(_("Stopped plugin {0}", app));
return;
}
// value
if (_action.startsWith("Update ")) {
String app = _action.substring(7);
updatePlugin(app);
return;
}
// value
if (_action.startsWith("Check ")) {
String app = _action.substring(6);
checkPlugin(app);
return;
}
// label (IE) // label (IE)
String xStart = _("Start"); String xStart = _("Start");
if (_action.toLowerCase().startsWith(xStart + "<span class=hide> ") && if (_action.toLowerCase().startsWith(xStart + "<span class=hide> ") &&
@ -81,6 +117,7 @@ public class ConfigClientsHandler extends FormHandler {
} else { } else {
addFormError(_("Unsupported") + ' ' + _action + '.'); addFormError(_("Unsupported") + ' ' + _action + '.');
} }
} }
public void setSettings(Map settings) { _settings = new HashMap(settings); } public void setSettings(Map settings) { _settings = new HashMap(settings); }
@ -175,7 +212,23 @@ public class ConfigClientsHandler extends FormHandler {
props.setProperty(name, "" + (val != null)); props.setProperty(name, "" + (val != null));
} }
RouterConsoleRunner.storeWebAppProperties(props); RouterConsoleRunner.storeWebAppProperties(props);
addFormNotice(_("WebApp configuration saved successfully - restart required to take effect.")); addFormNotice(_("WebApp configuration saved."));
}
private void savePluginChanges() {
Properties props = PluginStarter.pluginProperties();
Set keys = props.keySet();
int cur = 0;
for (Iterator iter = keys.iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
if (! (name.startsWith(PluginStarter.PREFIX) && name.endsWith(PluginStarter.ENABLED)))
continue;
String app = name.substring(PluginStarter.PREFIX.length(), name.lastIndexOf(PluginStarter.ENABLED));
Object val = _settings.get(app + ".enabled");
props.setProperty(name, "" + (val != null));
}
PluginStarter.storePluginProperties(props);
addFormNotice(_("Plugin configuration saved."));
} }
/** /**
@ -205,6 +258,20 @@ public class ConfigClientsHandler extends FormHandler {
addFormError(_("No plugin URL specified.")); addFormError(_("No plugin URL specified."));
return; return;
} }
installPlugin(url);
}
private void updatePlugin(String app) {
Properties props = PluginStarter.pluginProperties(_context, app);
String url = props.getProperty("updateURL");
if (url == null) {
addFormError(_("No update URL specified for {0}",app));
return;
}
installPlugin(url);
}
private void installPlugin(String url) {
if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) { if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) {
addFormError(_("Plugin or update download already in progress.")); addFormError(_("Plugin or update download already in progress."));
return; return;
@ -221,4 +288,23 @@ public class ConfigClientsHandler extends FormHandler {
Thread.sleep(1000); Thread.sleep(1000);
} catch (InterruptedException ie) {} } catch (InterruptedException ie) {}
} }
private void checkPlugin(String app) {
if ("true".equals(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS))) {
addFormError(_("Plugin or update download already in progress."));
return;
}
PluginUpdateChecker puc = PluginUpdateChecker.getInstance(_context);
if (puc.isRunning()) {
addFormError(_("Plugin or update download already in progress."));
return;
}
puc.update(app);
addFormNotice(_("Checking plugin {0} for updates", app));
// So that update() will post a status to the summary bar before we reload
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {}
}
} }

View File

@ -70,6 +70,10 @@ public class ConfigClientsHelper extends HelperBase {
return buf.toString(); return buf.toString();
} }
public boolean showPlugins() {
return PluginStarter.pluginsEnabled(_context);
}
public String getForm3() { public String getForm3() {
StringBuilder buf = new StringBuilder(1024); StringBuilder buf = new StringBuilder(1024);
buf.append("<table>\n"); buf.append("<table>\n");
@ -170,7 +174,7 @@ public class ConfigClientsHelper extends HelperBase {
if (ro) if (ro)
buf.append("disabled=\"true\" "); buf.append("disabled=\"true\" ");
} }
buf.append("/></td><td align=\"center\" width=\"15%\">"); buf.append("></td><td align=\"center\" width=\"15%\">");
if ((!enabled) && !edit) { if ((!enabled) && !edit) {
buf.append("<button type=\"submit\" name=\"action\" value=\"Start ").append(index).append("\" >" + _("Start") + "<span class=hide> ").append(index).append("</span></button>"); buf.append("<button type=\"submit\" name=\"action\" value=\"Start ").append(index).append("\" >" + _("Start") + "<span class=hide> ").append(index).append("</span></button>");
} }

View File

@ -19,6 +19,7 @@ import net.i2p.data.DataHelper;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.startup.ClientAppConfig; import net.i2p.router.startup.ClientAppConfig;
import net.i2p.router.startup.LoadClientAppsJob; import net.i2p.router.startup.LoadClientAppsJob;
import net.i2p.util.FileUtil;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.Translate; import net.i2p.util.Translate;
@ -41,6 +42,10 @@ public class PluginStarter implements Runnable {
_context = ctx; _context = ctx;
} }
static boolean pluginsEnabled(I2PAppContext ctx) {
return Boolean.valueOf(ctx.getProperty("router.enablePlugins")).booleanValue();
}
public void run() { public void run() {
startPlugins(_context); startPlugins(_context);
} }
@ -50,9 +55,9 @@ public class PluginStarter implements Runnable {
Properties props = pluginProperties(); Properties props = pluginProperties();
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) { for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
String name = (String)iter.next(); String name = (String)iter.next();
if (name.startsWith(PluginStarter.PREFIX) && name.endsWith(PluginStarter.ENABLED)) { if (name.startsWith(PREFIX) && name.endsWith(ENABLED)) {
if (Boolean.valueOf(props.getProperty(name)).booleanValue()) { if (Boolean.valueOf(props.getProperty(name)).booleanValue()) {
String app = name.substring(PluginStarter.PREFIX.length(), name.lastIndexOf(PluginStarter.ENABLED)); String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED));
try { try {
if (!startPlugin(ctx, app)) if (!startPlugin(ctx, app))
log.error("Failed to start plugin: " + app); log.error("Failed to start plugin: " + app);
@ -188,7 +193,6 @@ public class PluginStarter implements Runnable {
} }
} }
// remove summary bar link // remove summary bar link
Properties props = pluginProperties(ctx, appName); Properties props = pluginProperties(ctx, appName);
String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx)); String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
@ -200,6 +204,25 @@ public class PluginStarter implements Runnable {
return true; return true;
} }
/** @return true on success - call stopPlugin() first */
static boolean deletePlugin(RouterContext ctx, String appName) {
Log log = ctx.logManager().getLog(PluginStarter.class);
File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
log.error("Cannot stop nonexistent plugin: " + appName);
return false;
}
FileUtil.rmdir(pluginDir, false);
Properties props = pluginProperties();
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
if (name.startsWith(PREFIX + appName))
iter.remove();
}
storePluginProperties(props);
return true;
}
/** plugin.config */ /** plugin.config */
public static Properties pluginProperties(I2PAppContext ctx, String appName) { public static Properties pluginProperties(I2PAppContext ctx, String appName) {
File cfgFile = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName + '/' + "plugin.config"); File cfgFile = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName + '/' + "plugin.config");

View File

@ -62,14 +62,15 @@ public class PluginUpdateChecker extends UpdateHandler {
String oldVersion = props.getProperty("version"); String oldVersion = props.getProperty("version");
String xpi2pURL = props.getProperty("updateURL"); String xpi2pURL = props.getProperty("updateURL");
if (oldVersion == null || xpi2pURL == null) { if (oldVersion == null || xpi2pURL == null) {
updateStatus("<b>" + _("Cannot update, plugin {0} is not installed", appName) + "</b>"); updateStatus("<b>" + _("Cannot check, plugin {0} is not installed", appName) + "</b>");
return; return;
} }
if (_pluginUpdateCheckerRunner == null) if (_pluginUpdateCheckerRunner == null)
_pluginUpdateCheckerRunner = new PluginUpdateCheckerRunner(xpi2pURL); _pluginUpdateCheckerRunner = new PluginUpdateCheckerRunner();
if (_pluginUpdateCheckerRunner.isRunning()) if (_pluginUpdateCheckerRunner.isRunning())
return; return;
_xpi2pURL = xpi2pURL;
_appName = appName; _appName = appName;
_oldVersion = oldVersion; _oldVersion = oldVersion;
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true"); System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
@ -89,18 +90,16 @@ public class PluginUpdateChecker extends UpdateHandler {
} }
public class PluginUpdateCheckerRunner extends UpdateRunner implements Runnable, EepGet.StatusListener { public class PluginUpdateCheckerRunner extends UpdateRunner implements Runnable, EepGet.StatusListener {
String _updateURL;
ByteArrayOutputStream _baos; ByteArrayOutputStream _baos;
public PluginUpdateCheckerRunner(String url) { public PluginUpdateCheckerRunner() {
super(); super();
_updateURL = url;
_baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES); _baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
} }
@Override @Override
protected void update() { protected void update() {
updateStatus("<b>" + _("Checking plugin {0} for updates", _appName) + "</b>"); updateStatus("<b>" + _("Checking for update of plugin {0}", _appName) + "</b>");
// use the same settings as for updater // use the same settings as for updater
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);

View File

@ -90,11 +90,9 @@ public class PluginUpdateHandler extends UpdateHandler {
} }
public class PluginUpdateRunner extends UpdateRunner implements Runnable, EepGet.StatusListener { public class PluginUpdateRunner extends UpdateRunner implements Runnable, EepGet.StatusListener {
String _updateURL;
public PluginUpdateRunner(String url) { public PluginUpdateRunner(String url) {
super(); super();
_updateURL = url;
} }
@Override @Override
@ -287,7 +285,7 @@ public class PluginUpdateHandler extends UpdateHandler {
if (oldVersion == null || if (oldVersion == null ||
(new VersionComparator()).compare(oldVersion, version) >= 0) { (new VersionComparator()).compare(oldVersion, version) >= 0) {
to.delete(); to.delete();
updateStatus("<b>" + _("New plugin version {0} is not newer than installed plugin", version) + "</b>"); updateStatus("<b>" + _("Downloaded plugin version {0} is not newer than installed plugin", version) + "</b>");
return; return;
} }
minVersion = ConfigClientsHelper.stripHTML(props, "min-installed-version"); minVersion = ConfigClientsHelper.stripHTML(props, "min-installed-version");

View File

@ -189,8 +189,10 @@ public class RouterConsoleRunner {
List<RouterContext> contexts = RouterContext.listContexts(); List<RouterContext> contexts = RouterContext.listContexts();
if (contexts != null) { if (contexts != null) {
t = new I2PAppThread(new PluginStarter(contexts.get(0)), "PluginStarter", true); if (PluginStarter.pluginsEnabled(contexts.get(0))) {
t.start(); t = new I2PAppThread(new PluginStarter(contexts.get(0)), "PluginStarter", true);
t.start();
}
} }
} }

View File

@ -54,16 +54,20 @@ button span.hide{
<i><%=intl._("All changes require restart to take effect.")%></i> <i><%=intl._("All changes require restart to take effect.")%></i>
</p><hr><div class="formaction"> </p><hr><div class="formaction">
<input type="submit" name="action" value="<%=intl._("Save WebApp Configuration")%>" /> <input type="submit" name="action" value="<%=intl._("Save WebApp Configuration")%>" />
</div></div><h3><a name="webapp"></a><%=intl._("Plugin Configuration")%></h3><p> </div></div>
<% if (clientshelper.showPlugins()) { %>
<h3><a name="webapp"></a><%=intl._("Plugin Configuration")%></h3><p>
<%=intl._("The plugins listed below are started by the webConsole client.")%> <%=intl._("The plugins listed below are started by the webConsole client.")%>
</p><div class="wideload"><p> </p><div class="wideload"><p>
<jsp:getProperty name="clientshelper" property="form3" /> <jsp:getProperty name="clientshelper" property="form3" />
</p><hr><div class="formaction"> </p><hr><div class="formaction">
<input type="submit" name="action" value="<%=intl._("Save Plugin Configuration")%>" /> <input type="submit" name="action" value="<%=intl._("Save Plugin Configuration")%>" />
</div></div><h3><a name="plugin"></a><%=intl._("Plugin Installation")%></h3><p> </div></div><h3><a name="plugin"></a><%=intl._("Plugin Installation")%></h3><p>
<%=intl._("To install a plugin, enter the URL to download the plugin from:")%> <%=intl._("To install a plugin, enter the download URL:")%>
</p><div class="wideload"><p> </p><div class="wideload"><p>
<input type="text" size="60" name="pluginURL" > <input type="text" size="60" name="pluginURL" >
</p><hr><div class="formaction"> </p><hr><div class="formaction">
<input type="submit" name="action" value="<%=intl._("Install Plugin")%>" /> <input type="submit" name="action" value="<%=intl._("Install Plugin")%>" />
</div></div></form></div></div></body></html> </div></div>
<% } %>
</form></div></div></body></html>