From: David ‘Bombe’ Roden <bombe@pterodactylus.net>
Date: Thu, 14 Oct 2010 19:26:10 +0000 (+0200)
Subject: Add Sone downloader.
X-Git-Tag: 0.1-RC1~353
X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=adf590c0b33f1cc3f136d8d3a714f7051407535f;p=Sone.git

Add Sone downloader.
---

diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java
index dfa94d6..3c3a659 100644
--- a/src/main/java/net/pterodactylus/sone/core/Core.java
+++ b/src/main/java/net/pterodactylus/sone/core/Core.java
@@ -59,6 +59,9 @@ public class Core extends AbstractService {
 	/** Interface to freenet. */
 	private FreenetInterface freenetInterface;
 
+	/** The Sone downloader. */
+	private SoneDownloader soneDownloader;
+
 	/** The local Sones. */
 	private final Set<Sone> localSones = new HashSet<Sone>();
 
@@ -108,6 +111,7 @@ public class Core extends AbstractService {
 	 */
 	public Core freenetInterface(FreenetInterface freenetInterface) {
 		this.freenetInterface = freenetInterface;
+		soneDownloader = new SoneDownloader(freenetInterface);
 		return this;
 	}
 
@@ -150,6 +154,7 @@ public class Core extends AbstractService {
 			soneCache.put(sone.getId(), sone);
 			SoneInserter soneInserter = new SoneInserter(freenetInterface, sone);
 			soneInserter.start();
+			soneDownloader.addSone(sone);
 			soneInserters.put(sone, soneInserter);
 		}
 	}
@@ -241,6 +246,7 @@ public class Core extends AbstractService {
 	 */
 	@Override
 	protected void serviceStop() {
+		soneDownloader.stop();
 		/* stop all Sone inserters. */
 		for (SoneInserter soneInserter : soneInserters.values()) {
 			soneInserter.stop();
diff --git a/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java b/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java
index 05b1fba..dae6f68 100644
--- a/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java
+++ b/src/main/java/net/pterodactylus/sone/core/FreenetInterface.java
@@ -17,18 +17,29 @@
 
 package net.pterodactylus.sone.core;
 
+import java.net.MalformedURLException;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.util.logging.Logging;
 import net.pterodactylus.util.service.AbstractService;
+
+import com.db4o.ObjectContainer;
+
 import freenet.client.FetchException;
 import freenet.client.FetchResult;
 import freenet.client.HighLevelSimpleClient;
+import freenet.client.HighLevelSimpleClientImpl;
 import freenet.client.InsertException;
+import freenet.client.async.ClientContext;
+import freenet.client.async.USKCallback;
 import freenet.keys.FreenetURI;
+import freenet.keys.USK;
 import freenet.node.Node;
+import freenet.node.RequestStarter;
 
 /**
  * Contains all necessary functionality for interacting with the Freenet node.
@@ -41,12 +52,14 @@ public class FreenetInterface extends AbstractService {
 	private static final Logger logger = Logging.getLogger(FreenetInterface.class);
 
 	/** The node to interact with. */
-	@SuppressWarnings("unused")
 	private final Node node;
 
 	/** The high-level client to use for requests. */
 	private final HighLevelSimpleClient client;
 
+	/** The USK callbacks. */
+	private final Map<String, USKCallback> soneUskCallbacks = new HashMap<String, USKCallback>();
+
 	/**
 	 * Creates a new Freenet interface.
 	 *
@@ -116,4 +129,63 @@ public class FreenetInterface extends AbstractService {
 		}
 	}
 
+	/**
+	 * Registers the USK for the given Sone and notifies the given
+	 * {@link SoneDownloader} if an update was found.
+	 *
+	 * @param sone
+	 *            The Sone to watch
+	 * @param soneDownloader
+	 *            The Sone download to notify on updates
+	 */
+	public void registerUsk(final Sone sone, final SoneDownloader soneDownloader) {
+		try {
+			logger.log(Level.FINE, "Registering Sone “%s” for USK updates at %s…", new Object[] { sone, sone.getRequestUri().setMetaString(new String[] { "sone.xml" }) });
+			USKCallback uskCallback = new USKCallback() {
+
+				@Override
+				@SuppressWarnings("synthetic-access")
+				public void onFoundEdition(long edition, USK key, ObjectContainer objectContainer, ClientContext clientContext, boolean metadata, short codec, byte[] data, boolean newKnownGood, boolean newSlotToo) {
+					logger.log(Level.FINE, "Found USK update for Sone “%s” at %s.", new Object[] { sone, key });
+					if (newKnownGood) {
+						sone.updateUris(key.getURI());
+					}
+					soneDownloader.fetchSone(sone);
+				}
+
+				@Override
+				public short getPollingPriorityProgress() {
+					return RequestStarter.INTERACTIVE_PRIORITY_CLASS;
+				}
+
+				@Override
+				public short getPollingPriorityNormal() {
+					return RequestStarter.INTERACTIVE_PRIORITY_CLASS;
+				}
+			};
+			soneUskCallbacks.put(sone.getId(), uskCallback);
+			node.clientCore.uskManager.subscribe(USK.create(sone.getRequestUri()), uskCallback, true, (HighLevelSimpleClientImpl) client);
+		} catch (MalformedURLException mue1) {
+			logger.log(Level.WARNING, "Could not subscribe USK “" + sone.getRequestUri() + "”!", mue1);
+		}
+	}
+
+	/**
+	 * Unsubscribes the request URI of the given Sone.
+	 *
+	 * @param sone
+	 *            The Sone to unregister
+	 */
+	public void unregisterUsk(Sone sone) {
+		USKCallback uskCallback = soneUskCallbacks.remove(sone.getId());
+		if (uskCallback == null) {
+			return;
+		}
+		try {
+			node.clientCore.uskManager.unsubscribe(USK.create(sone.getRequestUri()), uskCallback);
+		} catch (MalformedURLException mue1) {
+			logger.log(Level.FINE, "Could not unsubscribe USK “" + sone.getRequestUri() + "”!", mue1);
+		}
+	}
+
 }
diff --git a/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java b/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
new file mode 100644
index 0000000..1a8f870
--- /dev/null
+++ b/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java
@@ -0,0 +1,100 @@
+/*
+ * Sone - SoneDownloader.java - Copyright © 2010 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.core;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.service.AbstractService;
+import freenet.client.FetchResult;
+
+/**
+ * The Sone downloader is responsible for download Sones as they are updated.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class SoneDownloader extends AbstractService {
+
+	/** The logger. */
+	private static final Logger logger = Logging.getLogger(SoneDownloader.class);
+
+	/** The Freenet interface. */
+	private final FreenetInterface freenetInterface;
+
+	/** The sones to update. */
+	private final Set<Sone> sones = new HashSet<Sone>();
+
+	/**
+	 * Creates a new Sone downloader.
+	 *
+	 * @param freenetInterface
+	 *            The Freenet interface
+	 */
+	public SoneDownloader(FreenetInterface freenetInterface) {
+		super("Sone Downloader");
+		this.freenetInterface = freenetInterface;
+	}
+
+	//
+	// ACTIONS
+	//
+
+	/**
+	 * Adds the given Sone to the set of Sones that will be watched for updates.
+	 *
+	 * @param sone
+	 *            The Sone to add
+	 */
+	public void addSone(Sone sone) {
+		if (sones.add(sone)) {
+			freenetInterface.registerUsk(sone, this);
+		}
+	}
+
+	/**
+	 * Fetches the updated Sone. This method is a callback method for
+	 * {@link FreenetInterface#registerUsk(Sone, SoneDownloader)}.
+	 *
+	 * @param sone
+	 *            The Sone to fetch
+	 */
+	public void fetchSone(Sone sone) {
+		logger.log(Level.FINE, "Starting fetch for Sone “%s” from %s…", new Object[] { sone, sone.getRequestUri().setMetaString(new String[] { "sone.xml" }) });
+		FetchResult fetchResult = freenetInterface.fetchUri(sone.getRequestUri().setMetaString(new String[] { "sone.xml" }));
+		logger.log(Level.FINEST, "Got %d bytes back.", fetchResult.size());
+	}
+
+	//
+	// SERVICE METHODS
+	//
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void serviceStop() {
+		for (Sone sone : sones) {
+			freenetInterface.unregisterUsk(sone);
+		}
+	}
+
+}