* 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();
return;
}
if (_action.equals(_("Save Plugin Configuration"))) {
savePluginChanges();
return;
}
if (_action.equals(_("Install Plugin"))) {
installPlugin();
return;
@ -60,10 +64,42 @@ public class ConfigClientsHandler extends FormHandler {
try {
appnum = Integer.parseInt(app);
} catch (NumberFormatException nfe) {}
if (appnum >= 0)
if (appnum >= 0) {
deleteClient(appnum);
} else {
try {
PluginStarter.stopPlugin(_context, app);
} catch (Exception e) {}
PluginStarter.deletePlugin(_context, app);
addFormNotice(_("Deleted plugin {0}", app));
}
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)
String xStart = _("Start");
if (_action.toLowerCase().startsWith(xStart + "<span class=hide> ") &&
@ -81,6 +117,7 @@ public class ConfigClientsHandler extends FormHandler {
} else {
addFormError(_("Unsupported") + ' ' + _action + '.');
}
}
public void setSettings(Map settings) { _settings = new HashMap(settings); }
@ -175,7 +212,23 @@ public class ConfigClientsHandler extends FormHandler {
props.setProperty(name, "" + (val != null));
}
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."));
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))) {
addFormError(_("Plugin or update download already in progress."));
return;
@ -221,4 +288,23 @@ public class ConfigClientsHandler extends FormHandler {
Thread.sleep(1000);
} 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();
}
public boolean showPlugins() {
return PluginStarter.pluginsEnabled(_context);
}
public String getForm3() {
StringBuilder buf = new StringBuilder(1024);
buf.append("<table>\n");
@ -170,7 +174,7 @@ public class ConfigClientsHelper extends HelperBase {
if (ro)
buf.append("disabled=\"true\" ");
}
buf.append("/></td><td align=\"center\" width=\"15%\">");
buf.append("></td><td align=\"center\" width=\"15%\">");
if ((!enabled) && !edit) {
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.startup.ClientAppConfig;
import net.i2p.router.startup.LoadClientAppsJob;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
import net.i2p.util.Translate;
@ -41,6 +42,10 @@ public class PluginStarter implements Runnable {
_context = ctx;
}
static boolean pluginsEnabled(I2PAppContext ctx) {
return Boolean.valueOf(ctx.getProperty("router.enablePlugins")).booleanValue();
}
public void run() {
startPlugins(_context);
}
@ -50,9 +55,9 @@ public class PluginStarter implements Runnable {
Properties props = pluginProperties();
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
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()) {
String app = name.substring(PluginStarter.PREFIX.length(), name.lastIndexOf(PluginStarter.ENABLED));
String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED));
try {
if (!startPlugin(ctx, app))
log.error("Failed to start plugin: " + app);
@ -188,7 +193,6 @@ public class PluginStarter implements Runnable {
}
}
// remove summary bar link
Properties props = pluginProperties(ctx, appName);
String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
@ -200,6 +204,25 @@ public class PluginStarter implements Runnable {
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 */
public static Properties pluginProperties(I2PAppContext ctx, String appName) {
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 xpi2pURL = props.getProperty("updateURL");
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;
}
if (_pluginUpdateCheckerRunner == null)
_pluginUpdateCheckerRunner = new PluginUpdateCheckerRunner(xpi2pURL);
_pluginUpdateCheckerRunner = new PluginUpdateCheckerRunner();
if (_pluginUpdateCheckerRunner.isRunning())
return;
_xpi2pURL = xpi2pURL;
_appName = appName;
_oldVersion = oldVersion;
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 {
String _updateURL;
ByteArrayOutputStream _baos;
public PluginUpdateCheckerRunner(String url) {
public PluginUpdateCheckerRunner() {
super();
_updateURL = url;
_baos = new ByteArrayOutputStream(TrustedUpdate.HEADER_BYTES);
}
@Override
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
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);

View File

@ -90,11 +90,9 @@ public class PluginUpdateHandler extends UpdateHandler {
}
public class PluginUpdateRunner extends UpdateRunner implements Runnable, EepGet.StatusListener {
String _updateURL;
public PluginUpdateRunner(String url) {
super();
_updateURL = url;
}
@Override
@ -287,7 +285,7 @@ public class PluginUpdateHandler extends UpdateHandler {
if (oldVersion == null ||
(new VersionComparator()).compare(oldVersion, version) >= 0) {
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;
}
minVersion = ConfigClientsHelper.stripHTML(props, "min-installed-version");

View File

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