X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fde%2Ftodesbaum%2Fjsite%2Fapplication%2FUpdateChecker.java;fp=src%2Fmain%2Fjava%2Fde%2Ftodesbaum%2Fjsite%2Fapplication%2FUpdateChecker.java;h=11be944a1b66bff55b487eff20bbb6a26b62f011;hb=38bdc433e50669e8244a63b5af59e597f88f1d29;hp=0000000000000000000000000000000000000000;hpb=f14b9fbe6d88e23920b10a75ebeba4d38390301b;p=jSite.git diff --git a/src/main/java/de/todesbaum/jsite/application/UpdateChecker.java b/src/main/java/de/todesbaum/jsite/application/UpdateChecker.java new file mode 100644 index 0000000..11be944 --- /dev/null +++ b/src/main/java/de/todesbaum/jsite/application/UpdateChecker.java @@ -0,0 +1,302 @@ +/* + * jSite - UpdateChecker.java - Copyright © 2008–2012 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.application; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.pterodactylus.util.io.Closer; +import de.todesbaum.jsite.main.Main; +import de.todesbaum.jsite.main.Version; +import de.todesbaum.util.freenet.fcp2.Client; +import de.todesbaum.util.freenet.fcp2.ClientGet; +import de.todesbaum.util.freenet.fcp2.Connection; +import de.todesbaum.util.freenet.fcp2.Message; +import de.todesbaum.util.freenet.fcp2.Persistence; +import de.todesbaum.util.freenet.fcp2.ReturnType; +import de.todesbaum.util.freenet.fcp2.Verbosity; + +/** + * Checks for newer versions of jSite. + * + * @author David ‘Bombe’ Roden <bombe@freenetproject.org> + */ +public class UpdateChecker implements Runnable { + + /** The logger. */ + private static final Logger logger = Logger.getLogger(UpdateChecker.class.getName()); + + /** Counter for connection names. */ + private static int counter = 0; + + /** The edition for the update check URL. */ + private static final int UPDATE_EDITION = 18; + + /** The URL for update checks. */ + private static final String UPDATE_KEY = "USK@e3myoFyp5avg6WYN16ImHri6J7Nj8980Fm~aQe4EX1U,QvbWT0ImE0TwLODTl7EoJx2NBnwDxTbLTE6zkB-eGPs,AQACAAE"; + + /** Object used for synchronization. */ + private final Object syncObject = new Object(); + + /** Update listeners. */ + private final List updateListeners = new ArrayList(); + + /** Whether the main thread should stop. */ + private boolean shouldStop = false; + + /** Current last found edition of update key. */ + private int lastUpdateEdition = UPDATE_EDITION; + + /** Last found version. */ + private Version lastVersion = Main.getVersion(); + + /** The freenet interface. */ + private final Freenet7Interface freenetInterface; + + /** + * Creates a new update checker that uses the given frame as its parent and + * communications via the given freenet interface. + * + * @param freenetInterface + * The freenet interface + */ + public UpdateChecker(Freenet7Interface freenetInterface) { + this.freenetInterface = freenetInterface; + } + + // + // EVENT LISTENER MANAGEMENT + // + + /** + * Adds an update listener to the list of registered listeners. + * + * @param updateListener + * The update listener to add + */ + public void addUpdateListener(UpdateListener updateListener) { + updateListeners.add(updateListener); + } + + /** + * Removes the given listener from the list of registered listeners. + * + * @param updateListener + * The update listener to remove + */ + public void removeUpdateListener(UpdateListener updateListener) { + updateListeners.remove(updateListener); + } + + /** + * Notifies all listeners that a version was found. + * + * @param foundVersion + * The version that was found + * @param versionTimestamp + * The timestamp of the version + */ + protected void fireUpdateFound(Version foundVersion, long versionTimestamp) { + for (UpdateListener updateListener : updateListeners) { + updateListener.foundUpdateData(foundVersion, versionTimestamp); + } + } + + // + // ACCESSORS + // + + /** + * Returns the latest version that was found. + * + * @return The latest found version + */ + public Version getLatestVersion() { + return lastVersion; + } + + // + // ACTIONS + // + + /** + * Starts the update checker. + */ + public void start() { + new Thread(this).start(); + } + + /** + * Stops the update checker. + */ + public void stop() { + synchronized (syncObject) { + shouldStop = true; + syncObject.notifyAll(); + } + } + + // + // PRIVATE METHODS + // + + /** + * Returns whether the update checker should stop. + * + * @return true if the update checker should stop, + * false otherwise + */ + private boolean shouldStop() { + synchronized (syncObject) { + return shouldStop; + } + } + + /** + * Creates the URI of the update file for the given edition. + * + * @param edition + * The edition number + * @return The URI for the update file for the given edition + */ + private static String constructUpdateKey(int edition) { + return UPDATE_KEY + "/jSite/" + edition + "/jSite.properties"; + } + + // + // INTERFACE Runnable + // + + /** + * {@inheritDoc} + */ + @Override + public void run() { + int currentEdition = lastUpdateEdition; + while (!shouldStop()) { + + /* try to connect. */ + Client client; + while (true) { + Connection connection = freenetInterface.getConnection("jSite-" + ++counter + "-UpdateChecker"); + try { + connection.connect(); + logger.log(Level.INFO, "Connected to " + freenetInterface.getNode() + "."); + client = new Client(connection); + break; + } catch (IOException ioe1) { + logger.log(Level.INFO, "Could not connect to " + freenetInterface.getNode() + ".", ioe1); + } + if (!connection.isConnected()) { + try { + Thread.sleep(60 * 1000); + } catch (InterruptedException ie1) { + /* ignore, we’re looping. */ + } + } + } + + boolean checkNow = false; + logger.log(Level.FINE, "Trying " + constructUpdateKey(currentEdition)); + ClientGet clientGet = new ClientGet("get-update-key"); + clientGet.setUri(constructUpdateKey(currentEdition)); + clientGet.setPersistence(Persistence.CONNECTION); + clientGet.setReturnType(ReturnType.direct); + clientGet.setVerbosity(Verbosity.ALL); + try { + client.execute(clientGet); + boolean stop = false; + while (!stop) { + Message message = client.readMessage(); + logger.log(Level.FINEST, "Received message: " + message); + if (message == null) { + break; + } + if ("GetFailed".equals(message.getName())) { + if ("27".equals(message.get("code"))) { + String editionString = message.get("redirecturi").split("/")[2]; + int editionNumber = -1; + try { + editionNumber = Integer.parseInt(editionString); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + if (editionNumber != -1) { + logger.log(Level.INFO, "Found new edition " + editionNumber); + currentEdition = editionNumber; + lastUpdateEdition = editionNumber; + checkNow = true; + break; + } + } + } + if ("AllData".equals(message.getName())) { + logger.log(Level.FINE, "Update data found."); + InputStream dataInputStream = null; + Properties properties = new Properties(); + try { + dataInputStream = message.getPayloadInputStream(); + properties.load(dataInputStream); + } finally { + Closer.close(dataInputStream); + } + + String foundVersionString = properties.getProperty("jSite.Version"); + if (foundVersionString != null) { + Version foundVersion = Version.parse(foundVersionString); + if (foundVersion != null) { + lastVersion = foundVersion; + String versionTimestampString = properties.getProperty("jSite.Date"); + logger.log(Level.FINEST, "Version timestamp: " + versionTimestampString); + long versionTimestamp = -1; + try { + versionTimestamp = Long.parseLong(versionTimestampString); + } catch (NumberFormatException nfe1) { + /* ignore. */ + } + fireUpdateFound(foundVersion, versionTimestamp); + stop = true; + checkNow = true; + ++currentEdition; + } + } + } + } + } catch (IOException e) { + logger.log(Level.INFO, "Got IOException: " + e.getMessage()); + e.printStackTrace(); + } + if (!checkNow && !shouldStop()) { + synchronized (syncObject) { + try { + syncObject.wait(15 * 60 * 1000); + } catch (InterruptedException ie1) { + /* ignore. */ + } + } + } + } + } + +}