forked from I2P_Developers/i2p.i2p
Add support for dmg and exe updates
This commit is contained in:
@@ -62,6 +62,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
private final Log _log;
|
private final Log _log;
|
||||||
private final Collection<RegisteredUpdater> _registeredUpdaters;
|
private final Collection<RegisteredUpdater> _registeredUpdaters;
|
||||||
private final Collection<RegisteredChecker> _registeredCheckers;
|
private final Collection<RegisteredChecker> _registeredCheckers;
|
||||||
|
private final Map<Integer, UpdatePostProcessor> _registeredPostProcessors;
|
||||||
/** active checking tasks */
|
/** active checking tasks */
|
||||||
private final Collection<UpdateTask> _activeCheckers;
|
private final Collection<UpdateTask> _activeCheckers;
|
||||||
/** active updating tasks, pointing to the next ones to try */
|
/** active updating tasks, pointing to the next ones to try */
|
||||||
@@ -95,6 +96,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
_log = ctx.logManager().getLog(ConsoleUpdateManager.class);
|
_log = ctx.logManager().getLog(ConsoleUpdateManager.class);
|
||||||
_registeredUpdaters = new ConcurrentHashSet<RegisteredUpdater>();
|
_registeredUpdaters = new ConcurrentHashSet<RegisteredUpdater>();
|
||||||
_registeredCheckers = new ConcurrentHashSet<RegisteredChecker>();
|
_registeredCheckers = new ConcurrentHashSet<RegisteredChecker>();
|
||||||
|
_registeredPostProcessors = new ConcurrentHashMap<Integer, UpdatePostProcessor>(2);
|
||||||
_activeCheckers = new ConcurrentHashSet<UpdateTask>();
|
_activeCheckers = new ConcurrentHashSet<UpdateTask>();
|
||||||
_downloaders = new ConcurrentHashMap<UpdateTask, List<RegisteredUpdater>>();
|
_downloaders = new ConcurrentHashMap<UpdateTask, List<RegisteredUpdater>>();
|
||||||
_available = new ConcurrentHashMap<UpdateItem, VersionAvailable>();
|
_available = new ConcurrentHashMap<UpdateItem, VersionAvailable>();
|
||||||
@@ -757,6 +759,20 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
_registeredCheckers.remove(rc);
|
_registeredCheckers.remove(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a post-processor for this UpdateType and SU3File file type.
|
||||||
|
*
|
||||||
|
* @param type only ROUTER_SIGNED_SU3 and ROUTER_DEV_SU3 are currently supported
|
||||||
|
* @param fileType a SU3File TYPE_xxx constant, 1-255, TYPE_ZIP not supported.
|
||||||
|
* @since 0.9.51
|
||||||
|
*/
|
||||||
|
public void register(UpdatePostProcessor upp, UpdateType type, int fileType) {
|
||||||
|
Integer key = Integer.valueOf(type.toString().hashCode() ^ fileType);
|
||||||
|
UpdatePostProcessor old = _registeredPostProcessors.put(key, upp);
|
||||||
|
if (old != null && _log.shouldLog(Log.WARN))
|
||||||
|
_log.warn("Duplicate registration " + upp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the Updater, either after check() was called, or it found out on its own.
|
* Called by the Updater, either after check() was called, or it found out on its own.
|
||||||
* Use this if there is only one UpdateMethod; otherwise use the Map method below.
|
* Use this if there is only one UpdateMethod; otherwise use the Map method below.
|
||||||
@@ -1102,7 +1118,8 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Updater " + task + " for " + task.getType() + " complete");
|
_log.info("Updater " + task + " for " + task.getType() + " complete");
|
||||||
boolean rv = false;
|
boolean rv = false;
|
||||||
switch (task.getType()) {
|
UpdateType utype = task.getType();
|
||||||
|
switch (utype) {
|
||||||
case TYPE_DUMMY:
|
case TYPE_DUMMY:
|
||||||
case NEWS:
|
case NEWS:
|
||||||
case NEWS_SU3:
|
case NEWS_SU3:
|
||||||
@@ -1110,13 +1127,13 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ROUTER_SIGNED:
|
case ROUTER_SIGNED:
|
||||||
rv = handleSudFile(task.getURI(), actualVersion, file);
|
rv = handleRouterFile(task.getURI(), actualVersion, file, utype);
|
||||||
if (rv)
|
if (rv)
|
||||||
notifyDownloaded(task.getType(), task.getID(), actualVersion);
|
notifyDownloaded(task.getType(), task.getID(), actualVersion);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ROUTER_SIGNED_SU3:
|
case ROUTER_SIGNED_SU3:
|
||||||
rv = handleSu3File(task.getURI(), actualVersion, file);
|
rv = handleRouterFile(task.getURI(), actualVersion, file, utype);
|
||||||
if (rv)
|
if (rv)
|
||||||
notifyDownloaded(task.getType(), task.getID(), actualVersion);
|
notifyDownloaded(task.getType(), task.getID(), actualVersion);
|
||||||
break;
|
break;
|
||||||
@@ -1130,7 +1147,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ROUTER_DEV_SU3:
|
case ROUTER_DEV_SU3:
|
||||||
rv = handleSu3File(task.getURI(), actualVersion, file);
|
rv = handleRouterFile(task.getURI(), actualVersion, file, utype);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
_context.router().saveConfig(PROP_DEV_SU3_AVAILABLE, null);
|
_context.router().saveConfig(PROP_DEV_SU3_AVAILABLE, null);
|
||||||
notifyDownloaded(task.getType(), task.getID(), actualVersion);
|
notifyDownloaded(task.getType(), task.getID(), actualVersion);
|
||||||
@@ -1325,47 +1342,48 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Process sud, su2, or su3.
|
||||||
|
* Only for router updates.
|
||||||
*
|
*
|
||||||
* @return success
|
|
||||||
*/
|
|
||||||
private boolean handleSudFile(URI uri, String actualVersion, File f) {
|
|
||||||
return handleRouterFile(uri, actualVersion, f, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return success
|
* @return success
|
||||||
* @since 0.9.9
|
* @since 0.9.9
|
||||||
*/
|
*/
|
||||||
private boolean handleSu3File(URI uri, String actualVersion, File f) {
|
private boolean handleRouterFile(URI uri, String actualVersion, File f, UpdateType updateType) {
|
||||||
return handleRouterFile(uri, actualVersion, f, true);
|
boolean isSU3 = updateType == ROUTER_SIGNED_SU3 || updateType == ROUTER_DEV_SU3;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process sud, su2, or su3
|
|
||||||
* @return success
|
|
||||||
* @since 0.9.9
|
|
||||||
*/
|
|
||||||
private boolean handleRouterFile(URI uri, String actualVersion, File f, boolean isSU3) {
|
|
||||||
String url = uri.toString();
|
String url = uri.toString();
|
||||||
updateStatus("<b>" + _t("Update downloaded") + "</b>");
|
updateStatus("<b>" + _t("Update downloaded") + "</b>");
|
||||||
File to = new File(_context.getRouterDir(), Router.UPDATE_FILE);
|
File to = new File(_context.getRouterDir(), Router.UPDATE_FILE);
|
||||||
String err;
|
String err = null;
|
||||||
// Process the file
|
// Process the file
|
||||||
if (isSU3) {
|
if (isSU3) {
|
||||||
SU3File up = new SU3File(_context, f);
|
SU3File up = new SU3File(_context, f);
|
||||||
File temp = new File(_context.getTempDir(), "su3out-" + _context.random().nextLong() + ".zip");
|
File temp = new File(_context.getTempDir(), "su3out-" + _context.random().nextLong());
|
||||||
try {
|
try {
|
||||||
if (up.verifyAndMigrate(temp)) {
|
if (up.verifyAndMigrate(temp)) {
|
||||||
String ver = up.getVersionString();
|
String ver = up.getVersionString();
|
||||||
int type = up.getContentType();
|
int type = up.getContentType();
|
||||||
if (ver == null || VersionComparator.comp(RouterVersion.VERSION, ver) >= 0)
|
if (ver == null || VersionComparator.comp(RouterVersion.VERSION, ver) >= 0) {
|
||||||
err = "Old version " + ver;
|
err = "Old version " + ver;
|
||||||
else if (type != SU3File.CONTENT_ROUTER)
|
} else if (type != SU3File.CONTENT_ROUTER) {
|
||||||
err = "Bad su3 content type " + type;
|
err = "Bad su3 content type " + type;
|
||||||
else if (!FileUtil.copy(temp, to, true, false))
|
} else {
|
||||||
|
int ftype = up.getFileType();
|
||||||
|
if (ftype == SU3File.TYPE_ZIP) {
|
||||||
|
// standard update, copy to i2pupdate.zip in config dir
|
||||||
|
if (!FileUtil.copy(temp, to, true, false))
|
||||||
err = "Failed copy to " + to;
|
err = "Failed copy to " + to;
|
||||||
|
} else if ((ftype == SU3File.TYPE_DMG && SystemVersion.isMac()) ||
|
||||||
|
(ftype == SU3File.TYPE_EXE && SystemVersion.isWindows())) {
|
||||||
|
Integer key = Integer.valueOf(updateType.toString().hashCode() ^ ftype);
|
||||||
|
UpdatePostProcessor upp = _registeredPostProcessors.get(key);
|
||||||
|
if (upp != null)
|
||||||
|
upp.updateDownloadedandVerified(updateType, ftype, actualVersion, temp);
|
||||||
else
|
else
|
||||||
err = null; // success
|
err = "Unsupported su3 file type " + ftype;
|
||||||
|
} else {
|
||||||
|
err = "Unsupported su3 file type " + ftype;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
err = "Signature failed, signer " + DataHelper.stripHTML(up.getSignerString()) +
|
err = "Signature failed, signer " + DataHelper.stripHTML(up.getSignerString()) +
|
||||||
' ' + up.getSigType();
|
' ' + up.getSigType();
|
||||||
@@ -1406,6 +1424,8 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Only for router updates
|
||||||
|
*
|
||||||
* @param Long.toString(timestamp)
|
* @param Long.toString(timestamp)
|
||||||
* @return success
|
* @return success
|
||||||
*/
|
*/
|
||||||
@@ -1755,6 +1775,10 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
|
|||||||
buf.append("<div class=\"debug_container\">");
|
buf.append("<div class=\"debug_container\">");
|
||||||
toString(buf, _registeredUpdaters);
|
toString(buf, _registeredUpdaters);
|
||||||
buf.append("</div>");
|
buf.append("</div>");
|
||||||
|
buf.append("<h3>Registered PostProcessors</h3>");
|
||||||
|
buf.append("<div class=\"debug_container\">");
|
||||||
|
toString(buf, _registeredPostProcessors.values());
|
||||||
|
buf.append("</div>");
|
||||||
buf.append("<h3>Active Checkers</h3>");
|
buf.append("<h3>Active Checkers</h3>");
|
||||||
buf.append("<div class=\"debug_container\">");
|
buf.append("<div class=\"debug_container\">");
|
||||||
toString(buf, _activeCheckers);
|
toString(buf, _activeCheckers);
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ public class SU3File {
|
|||||||
public static final int TYPE_XML_GZ = 3;
|
public static final int TYPE_XML_GZ = 3;
|
||||||
/** @since 0.9.28 */
|
/** @since 0.9.28 */
|
||||||
public static final int TYPE_TXT_GZ = 4;
|
public static final int TYPE_TXT_GZ = 4;
|
||||||
|
/** @since 0.9.51 */
|
||||||
|
public static final int TYPE_DMG = 5;
|
||||||
|
/** @since 0.9.51 */
|
||||||
|
public static final int TYPE_EXE = 6;
|
||||||
|
|
||||||
public static final int CONTENT_UNKNOWN = 0;
|
public static final int CONTENT_UNKNOWN = 0;
|
||||||
public static final int CONTENT_ROUTER = 1;
|
public static final int CONTENT_ROUTER = 1;
|
||||||
@@ -703,7 +707,9 @@ public class SU3File {
|
|||||||
" HTML\t(code: 2)\n" +
|
" HTML\t(code: 2)\n" +
|
||||||
" XML_GZ\t(code: 3)\n" +
|
" XML_GZ\t(code: 3)\n" +
|
||||||
" TXT_GZ\t(code: 4)\n" +
|
" TXT_GZ\t(code: 4)\n" +
|
||||||
" (user defined)\t(code: 5-255)\n");
|
" DMG\t(code: 5)\n" +
|
||||||
|
" EXE\t(code: 6)\n" +
|
||||||
|
" (user defined)\t(code: 7-255)\n");
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,6 +767,10 @@ public class SU3File {
|
|||||||
ftype = "HTML";
|
ftype = "HTML";
|
||||||
else if (file._fileType == TYPE_XML_GZ)
|
else if (file._fileType == TYPE_XML_GZ)
|
||||||
ftype = "XML_GZ";
|
ftype = "XML_GZ";
|
||||||
|
else if (file._fileType == TYPE_DMG)
|
||||||
|
ftype = "DMG";
|
||||||
|
else if (file._fileType == TYPE_EXE)
|
||||||
|
ftype = "EXE";
|
||||||
else
|
else
|
||||||
ftype = Integer.toString(file._fileType);
|
ftype = Integer.toString(file._fileType);
|
||||||
System.out.println("FileType: " + ftype);
|
System.out.println("FileType: " + ftype);
|
||||||
@@ -861,6 +871,10 @@ public class SU3File {
|
|||||||
ft = TYPE_HTML;
|
ft = TYPE_HTML;
|
||||||
} else if (ftype.equalsIgnoreCase("XML_GZ")) {
|
} else if (ftype.equalsIgnoreCase("XML_GZ")) {
|
||||||
ft = TYPE_XML_GZ;
|
ft = TYPE_XML_GZ;
|
||||||
|
} else if (ftype.equalsIgnoreCase("DMG")) {
|
||||||
|
ft = TYPE_DMG;
|
||||||
|
} else if (ftype.equalsIgnoreCase("EXE")) {
|
||||||
|
ft = TYPE_EXE;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
ft = Integer.parseInt(ftype);
|
ft = Integer.parseInt(ftype);
|
||||||
@@ -975,6 +989,12 @@ public class SU3File {
|
|||||||
case TYPE_TXT_GZ:
|
case TYPE_TXT_GZ:
|
||||||
sfx = ".txt.gz";
|
sfx = ".txt.gz";
|
||||||
break;
|
break;
|
||||||
|
case TYPE_DMG:
|
||||||
|
sfx = ".dmg";
|
||||||
|
break;
|
||||||
|
case TYPE_EXE:
|
||||||
|
sfx = ".exe";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sfx = ".extracted";
|
sfx = ".extracted";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -35,6 +35,15 @@ public interface UpdateManager {
|
|||||||
|
|
||||||
public void unregister(Checker checker, UpdateType type, UpdateMethod method);
|
public void unregister(Checker checker, UpdateType type, UpdateMethod method);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a post-processor for this UpdateType and SU3File file type.
|
||||||
|
*
|
||||||
|
* @param type only ROUTER_SIGNED_SU3 and ROUTER_DEV_SU3 are currently supported
|
||||||
|
* @param fileType a SU3File TYPE_xxx constant, 1-255, TYPE_ZIP not supported.
|
||||||
|
* @since 0.9.51
|
||||||
|
*/
|
||||||
|
public void register(UpdatePostProcessor upp, UpdateType type, int fileType);
|
||||||
|
|
||||||
public void start();
|
public void start();
|
||||||
|
|
||||||
public void shutdown();
|
public void shutdown();
|
||||||
|
|||||||
50
core/java/src/net/i2p/update/UpdatePostProcessor.java
Normal file
50
core/java/src/net/i2p/update/UpdatePostProcessor.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package net.i2p.update;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An external class to handle complex processing of update files,
|
||||||
|
* where necessary instead of simply copying i2pupdate.zip to the config dir.
|
||||||
|
*
|
||||||
|
* @since 0.9.51
|
||||||
|
*/
|
||||||
|
public interface UpdatePostProcessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify the post-processor that an update has been downloaded and verified.
|
||||||
|
* The version will be higher than the currently-installed version.
|
||||||
|
*
|
||||||
|
* This method MUST immediately postprocess, copy, or rename the file, which
|
||||||
|
* will be located in the temporary directory.
|
||||||
|
* Caller will delete the file if it remains, immediately after this method returns.
|
||||||
|
*
|
||||||
|
* This method MUST throw an IOException on all errors. The IOException will be
|
||||||
|
* displayed to the user in the console, so it should be clear.
|
||||||
|
*
|
||||||
|
* This method must not trigger the shutdown itself.
|
||||||
|
* Caller will trigger the shutdown if so configured.
|
||||||
|
*
|
||||||
|
* If the post-processor needs to perform any actions at shutdown, it should
|
||||||
|
* call I2PAppContext.addShutdownTask() or RouterContext.addFinalShutdownTask().
|
||||||
|
* See javadocs for restrictions on final shutdown tasks.
|
||||||
|
* Note that the router's temporary directory is deleted at shutdown,
|
||||||
|
* BEFORE the final shutdown tasks are run.
|
||||||
|
*
|
||||||
|
* After this call, the router will do a graceful shutdown if so configured,
|
||||||
|
* or will notify the user in the console to manually shut down the router.
|
||||||
|
* Therefore, the shutdown may happen immediately, or be delayed for 10 minutes,
|
||||||
|
* or may be hours, days, or weeks later.
|
||||||
|
*
|
||||||
|
* In rare cases, a newer update may be downloaded before the shutdown
|
||||||
|
* for the first update, and this method may be called again with the newer version.
|
||||||
|
* Implementers must take care to properly handle multiple calls.
|
||||||
|
*
|
||||||
|
* @param type only ROUTER_SIGNED_SU3 and ROUTER_DEV_SU3 are currently supported
|
||||||
|
* @param fileType a TYPE_xxx file type code from the SU3File, 0-255
|
||||||
|
* @param version the version string from the SU3File
|
||||||
|
* @param file in the temp directory, as extracted from the validated su3 file
|
||||||
|
* @throws IOException on all errors, message will be displayed to the user
|
||||||
|
*/
|
||||||
|
public void updateDownloadedandVerified(UpdateType type, int fileType, String version, File file) throws IOException;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user