From adf590c0b33f1cc3f136d8d3a714f7051407535f Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Thu, 14 Oct 2010 21:26:10 +0200 Subject: [PATCH] Add Sone downloader. --- .../java/net/pterodactylus/sone/core/Core.java | 6 ++ .../pterodactylus/sone/core/FreenetInterface.java | 74 ++++++++++++++- .../pterodactylus/sone/core/SoneDownloader.java | 100 +++++++++++++++++++++ 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 src/main/java/net/pterodactylus/sone/core/SoneDownloader.java 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 localSones = new HashSet(); @@ -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 soneUskCallbacks = new HashMap(); + /** * 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 . + */ + +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 David ‘Bombe’ Roden + */ +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 sones = new HashSet(); + + /** + * 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); + } + } + +} -- 2.7.4