/** Interface to freenet. */
private FreenetInterface freenetInterface;
+ /** The Sone downloader. */
+ private SoneDownloader soneDownloader;
+
/** The local Sones. */
private final Set<Sone> localSones = new HashSet<Sone>();
*/
public Core freenetInterface(FreenetInterface freenetInterface) {
this.freenetInterface = freenetInterface;
+ soneDownloader = new SoneDownloader(freenetInterface);
return this;
}
soneCache.put(sone.getId(), sone);
SoneInserter soneInserter = new SoneInserter(freenetInterface, sone);
soneInserter.start();
+ soneDownloader.addSone(sone);
soneInserters.put(sone, soneInserter);
}
}
*/
@Override
protected void serviceStop() {
+ soneDownloader.stop();
/* stop all Sone inserters. */
for (SoneInserter soneInserter : soneInserters.values()) {
soneInserter.stop();
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.
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.
*
}
}
+ /**
+ * 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);
+ }
+ }
+
}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+
+}