forked from I2P_Developers/i2p.i2p
* Plugins:
- Auto-update plugins after a router update - Add update-all button
This commit is contained in:
@ -53,6 +53,10 @@ public class ConfigClientsHandler extends FormHandler {
|
|||||||
installPlugin();
|
installPlugin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (_action.equals(_("Update All Installed Plugins"))) {
|
||||||
|
updateAllPlugins();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// value
|
// value
|
||||||
if (_action.startsWith("Start ")) {
|
if (_action.startsWith("Start ")) {
|
||||||
String app = _action.substring(6);
|
String app = _action.substring(6);
|
||||||
@ -321,6 +325,16 @@ public class ConfigClientsHandler extends FormHandler {
|
|||||||
installPlugin(url);
|
installPlugin(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.8.13 */
|
||||||
|
private void updateAllPlugins() {
|
||||||
|
addFormNotice(_("Updating all plugins"));
|
||||||
|
PluginStarter.updateAll(_context);
|
||||||
|
// So that update() will post a status to the summary bar before we reload
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
|
|
||||||
private void installPlugin(String 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."));
|
||||||
|
@ -22,10 +22,12 @@ import net.i2p.I2PAppContext;
|
|||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.router.Job;
|
import net.i2p.router.Job;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
|
import net.i2p.router.RouterVersion;
|
||||||
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.ConcurrentHashSet;
|
import net.i2p.util.ConcurrentHashSet;
|
||||||
import net.i2p.util.FileUtil;
|
import net.i2p.util.FileUtil;
|
||||||
|
import net.i2p.util.I2PAppThread;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.Translate;
|
import net.i2p.util.Translate;
|
||||||
import net.i2p.util.VersionComparator;
|
import net.i2p.util.VersionComparator;
|
||||||
@ -63,9 +65,96 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
if (_context.getBooleanPropertyDefaultTrue("plugins.autoUpdate") &&
|
||||||
|
(!Boolean.valueOf(System.getProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS)).booleanValue()) &&
|
||||||
|
(!RouterVersion.VERSION.equals(_context.getProperty("router.previousVersion"))))
|
||||||
|
updateAll(_context, true);
|
||||||
startPlugins(_context);
|
startPlugins(_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* threaded
|
||||||
|
* @since 0.8.13
|
||||||
|
*/
|
||||||
|
static void updateAll(RouterContext ctx) {
|
||||||
|
Thread t = new I2PAppThread(new PluginUpdater(ctx), "PluginUpdater", true);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* thread
|
||||||
|
* @since 0.8.13
|
||||||
|
*/
|
||||||
|
private static class PluginUpdater implements Runnable {
|
||||||
|
private final RouterContext _ctx;
|
||||||
|
|
||||||
|
public PluginUpdater(RouterContext ctx) {
|
||||||
|
_ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
updateAll(_ctx, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inline
|
||||||
|
* @since 0.8.13
|
||||||
|
*/
|
||||||
|
private static void updateAll(RouterContext ctx, boolean delay) {
|
||||||
|
List<String> plugins = getPlugins();
|
||||||
|
Map<String, String> toUpdate = new HashMap();
|
||||||
|
for (String appName : plugins) {
|
||||||
|
Properties props = pluginProperties(ctx, appName);
|
||||||
|
String url = props.getProperty("updateURL");
|
||||||
|
if (url != null)
|
||||||
|
toUpdate.put(appName, url);
|
||||||
|
}
|
||||||
|
if (toUpdate.isEmpty())
|
||||||
|
return;
|
||||||
|
PluginUpdateChecker puc = PluginUpdateChecker.getInstance(ctx);
|
||||||
|
if (puc.isRunning())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (delay) {
|
||||||
|
// wait for proxy
|
||||||
|
System.setProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS, "true");
|
||||||
|
puc.setAppStatus(Messages.getString("Checking for plugin updates", ctx));
|
||||||
|
try {
|
||||||
|
Thread.sleep(3*60*1000);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
System.setProperty(UpdateHandler.PROP_UPDATE_IN_PROGRESS, "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
Log log = ctx.logManager().getLog(PluginStarter.class);
|
||||||
|
for (Map.Entry<String, String> entry : toUpdate.entrySet()) {
|
||||||
|
String appName = entry.getKey();
|
||||||
|
if (log.shouldLog(Log.WARN))
|
||||||
|
log.warn("Checking for update plugin: " + appName);
|
||||||
|
puc.update(appName);
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
Thread.sleep(5*1000);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
} while (puc.isRunning());
|
||||||
|
if (!puc.isNewerAvailable()) {
|
||||||
|
if (log.shouldLog(Log.WARN))
|
||||||
|
log.warn("No update available for plugin: " + appName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PluginUpdateHandler puh = PluginUpdateHandler.getInstance(ctx);
|
||||||
|
String url = entry.getValue();
|
||||||
|
if (log.shouldLog(Log.WARN))
|
||||||
|
log.warn("Updating plugin: " + appName);
|
||||||
|
puh.update(url);
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
Thread.sleep(5*1000);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
} while (puh.isRunning());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** this shouldn't throw anything */
|
/** this shouldn't throw anything */
|
||||||
static void startPlugins(RouterContext ctx) {
|
static void startPlugins(RouterContext ctx) {
|
||||||
Log log = ctx.logManager().getLog(PluginStarter.class);
|
Log log = ctx.logManager().getLog(PluginStarter.class);
|
||||||
@ -75,6 +164,9 @@ public class PluginStarter implements Runnable {
|
|||||||
if (name.startsWith(PREFIX) && name.endsWith(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(PREFIX.length(), name.lastIndexOf(ENABLED));
|
String app = name.substring(PREFIX.length(), name.lastIndexOf(ENABLED));
|
||||||
|
// plugins could have been started after update
|
||||||
|
if (isPluginRunning(app, ctx))
|
||||||
|
continue;
|
||||||
try {
|
try {
|
||||||
if (!startPlugin(ctx, app))
|
if (!startPlugin(ctx, app))
|
||||||
log.error("Failed to start plugin: " + app);
|
log.error("Failed to start plugin: " + app);
|
||||||
|
@ -36,6 +36,7 @@ public class PluginUpdateChecker extends UpdateHandler {
|
|||||||
private String _appName;
|
private String _appName;
|
||||||
private String _oldVersion;
|
private String _oldVersion;
|
||||||
private String _xpi2pURL;
|
private String _xpi2pURL;
|
||||||
|
private volatile boolean _isNewerAvailable;
|
||||||
|
|
||||||
private static PluginUpdateChecker _instance;
|
private static PluginUpdateChecker _instance;
|
||||||
public static final synchronized PluginUpdateChecker getInstance(RouterContext ctx) {
|
public static final synchronized PluginUpdateChecker getInstance(RouterContext ctx) {
|
||||||
@ -49,12 +50,19 @@ public class PluginUpdateChecker extends UpdateHandler {
|
|||||||
super(ctx);
|
super(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** check all plugins */
|
/**
|
||||||
|
* check all plugins
|
||||||
|
* @deprecated not finished
|
||||||
|
*/
|
||||||
public void update() {
|
public void update() {
|
||||||
Thread t = new I2PAppThread(new AllCheckerRunner(), "AllAppChecker", true);
|
Thread t = new I2PAppThread(new AllCheckerRunner(), "AllAppChecker", true);
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check all plugins
|
||||||
|
* @deprecated not finished
|
||||||
|
*/
|
||||||
public class AllCheckerRunner implements Runnable {
|
public class AllCheckerRunner implements Runnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
List<String> plugins = PluginStarter.getPlugins();
|
List<String> plugins = PluginStarter.getPlugins();
|
||||||
@ -85,12 +93,18 @@ public class PluginUpdateChecker extends UpdateHandler {
|
|||||||
_xpi2pURL = xpi2pURL;
|
_xpi2pURL = xpi2pURL;
|
||||||
_appName = appName;
|
_appName = appName;
|
||||||
_oldVersion = oldVersion;
|
_oldVersion = oldVersion;
|
||||||
|
_isNewerAvailable = false;
|
||||||
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
|
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
|
||||||
I2PAppThread update = new I2PAppThread(_pluginUpdateCheckerRunner, "AppChecker", true);
|
I2PAppThread update = new I2PAppThread(_pluginUpdateCheckerRunner, "AppChecker", true);
|
||||||
update.start();
|
update.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.8.13 */
|
||||||
|
public void setAppStatus(String status) {
|
||||||
|
updateStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return _pluginUpdateCheckerRunner != null && _pluginUpdateCheckerRunner.isRunning();
|
return _pluginUpdateCheckerRunner != null && _pluginUpdateCheckerRunner.isRunning();
|
||||||
}
|
}
|
||||||
@ -101,6 +115,11 @@ public class PluginUpdateChecker extends UpdateHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 0.8.13 */
|
||||||
|
public boolean isNewerAvailable() {
|
||||||
|
return _isNewerAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
private void scheduleStatusClean(String msg) {
|
private void scheduleStatusClean(String msg) {
|
||||||
SimpleScheduler.getInstance().addEvent(new Cleaner(msg), 60*60*1000);
|
SimpleScheduler.getInstance().addEvent(new Cleaner(msg), 60*60*1000);
|
||||||
}
|
}
|
||||||
@ -126,6 +145,7 @@ public class PluginUpdateChecker extends UpdateHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void update() {
|
protected void update() {
|
||||||
|
_isNewerAvailable = false;
|
||||||
updateStatus("<b>" + _("Checking for update of plugin {0}", _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
|
||||||
// always proxy, or else FIXME
|
// always proxy, or else FIXME
|
||||||
@ -142,6 +162,10 @@ public class PluginUpdateChecker extends UpdateHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNewerAvailable() {
|
||||||
|
return _isNewerAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||||
}
|
}
|
||||||
@ -151,10 +175,12 @@ public class PluginUpdateChecker extends UpdateHandler {
|
|||||||
String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
|
String newVersion = TrustedUpdate.getVersionString(new ByteArrayInputStream(_baos.toByteArray()));
|
||||||
boolean newer = (new VersionComparator()).compare(newVersion, _oldVersion) > 0;
|
boolean newer = (new VersionComparator()).compare(newVersion, _oldVersion) > 0;
|
||||||
String msg;
|
String msg;
|
||||||
if (newer)
|
if (newer) {
|
||||||
msg = "<b>" + _("New plugin version {0} is available", newVersion) + "</b>";
|
msg = "<b>" + _("New plugin version {0} is available", newVersion) + "</b>";
|
||||||
else
|
_isNewerAvailable = true;
|
||||||
|
} else {
|
||||||
msg = "<b>" + _("No new version is available for plugin {0}", _appName) + "</b>";
|
msg = "<b>" + _("No new version is available for plugin {0}", _appName) + "</b>";
|
||||||
|
}
|
||||||
updateStatus(msg);
|
updateStatus(msg);
|
||||||
scheduleStatusClean(msg);
|
scheduleStatusClean(msg);
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ public class PluginUpdateHandler extends UpdateHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleStatusClean(String msg) {
|
private void scheduleStatusClean(String msg) {
|
||||||
SimpleScheduler.getInstance().addEvent(new Cleaner(msg), 60*60*1000);
|
SimpleScheduler.getInstance().addEvent(new Cleaner(msg), 20*60*1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Cleaner implements SimpleTimer.TimedEvent {
|
private class Cleaner implements SimpleTimer.TimedEvent {
|
||||||
|
@ -127,7 +127,7 @@ public class UpdateHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class UpdateRunner implements Runnable, EepGet.StatusListener {
|
public class UpdateRunner implements Runnable, EepGet.StatusListener {
|
||||||
protected boolean _isRunning;
|
protected volatile boolean _isRunning;
|
||||||
protected boolean done;
|
protected boolean done;
|
||||||
protected EepGet _get;
|
protected EepGet _get;
|
||||||
protected final DecimalFormat _pct = new DecimalFormat("0.0%");
|
protected final DecimalFormat _pct = new DecimalFormat("0.0%");
|
||||||
|
@ -103,6 +103,7 @@ button span.hide{
|
|||||||
<jsp:getProperty name="clientshelper" property="form2" />
|
<jsp:getProperty name="clientshelper" property="form2" />
|
||||||
<p><i><%=intl._("All changes require restart to take effect.")%></i>
|
<p><i><%=intl._("All changes require restart to take effect.")%></i>
|
||||||
</p><hr><div class="formaction">
|
</p><hr><div class="formaction">
|
||||||
|
<input type="submit" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
|
||||||
<input type="submit" name="action" class="accept" value="<%=intl._("Save WebApp Configuration")%>" />
|
<input type="submit" name="action" class="accept" value="<%=intl._("Save WebApp Configuration")%>" />
|
||||||
</div></form></div>
|
</div></form></div>
|
||||||
|
|
||||||
@ -114,6 +115,7 @@ button span.hide{
|
|||||||
<input type="hidden" name="nonce" value="<%=pageNonce%>" >
|
<input type="hidden" name="nonce" value="<%=pageNonce%>" >
|
||||||
<jsp:getProperty name="clientshelper" property="form3" />
|
<jsp:getProperty name="clientshelper" property="form3" />
|
||||||
<hr><div class="formaction">
|
<hr><div class="formaction">
|
||||||
|
<input type="submit" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
|
||||||
<input type="submit" name="action" class="accept" value="<%=intl._("Save Plugin Configuration")%>" />
|
<input type="submit" name="action" class="accept" value="<%=intl._("Save Plugin Configuration")%>" />
|
||||||
</div></form></div>
|
</div></form></div>
|
||||||
|
|
||||||
@ -125,7 +127,9 @@ button span.hide{
|
|||||||
<p>
|
<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" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
|
||||||
<input type="submit" name="action" class="download" value="<%=intl._("Install Plugin")%>" />
|
<input type="submit" name="action" class="download" value="<%=intl._("Install Plugin")%>" />
|
||||||
|
<input type="submit" name="action" class="reload" value="<%=intl._("Update All Installed Plugins")%>" />
|
||||||
</div></form></div>
|
</div></form></div>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div></div></body></html>
|
</div></div></body></html>
|
||||||
|
Reference in New Issue
Block a user