Add background fetch to freenet interface
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 11 Nov 2016 06:27:57 +0000 (07:27 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 11 Nov 2016 07:10:01 +0000 (08:10 +0100)
src/main/java/net/pterodactylus/sone/core/FreenetInterface.java
src/test/java/net/pterodactylus/sone/core/FreenetInterfaceTest.java

index 9b061c2..c6c4e97 100644 (file)
@@ -23,6 +23,7 @@ import static java.util.logging.Level.WARNING;
 import static java.util.logging.Logger.getLogger;
 import static net.pterodactylus.sone.freenet.Key.routingKey;
 
+import java.io.IOException;
 import java.net.MalformedURLException;
 import java.util.Collections;
 import java.util.HashMap;
@@ -30,6 +31,8 @@ import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.annotation.Nonnull;
+
 import net.pterodactylus.sone.core.event.ImageInsertAbortedEvent;
 import net.pterodactylus.sone.core.event.ImageInsertFailedEvent;
 import net.pterodactylus.sone.core.event.ImageInsertFinishedEvent;
@@ -44,6 +47,7 @@ import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
 import freenet.client.ClientMetadata;
+import freenet.client.FetchContext;
 import freenet.client.FetchException;
 import freenet.client.FetchException.FetchExceptionMode;
 import freenet.client.FetchResult;
@@ -53,6 +57,8 @@ import freenet.client.InsertContext;
 import freenet.client.InsertException;
 import freenet.client.async.BaseClientPutter;
 import freenet.client.async.ClientContext;
+import freenet.client.async.ClientGetCallback;
+import freenet.client.async.ClientGetter;
 import freenet.client.async.ClientPutCallback;
 import freenet.client.async.ClientPutter;
 import freenet.client.async.USKCallback;
@@ -95,6 +101,7 @@ public class FreenetInterface {
        private final Map<FreenetURI, USKCallback> uriUskCallbacks = Collections.synchronizedMap(new HashMap<FreenetURI, USKCallback>());
 
        private final RequestClient imageInserts = new RequestClientBuilder().realTime().build();
+       private final RequestClient imageLoader = new RequestClientBuilder().realTime().build();
 
        /**
         * Creates a new Freenet interface.
@@ -139,6 +146,45 @@ public class FreenetInterface {
                }
        }
 
+       public void startFetch(final FreenetURI uri, final BackgroundFetchCallback backgroundFetchCallback) {
+               ClientGetCallback callback = new ClientGetCallback() {
+                       @Override
+                       public void onSuccess(FetchResult result, ClientGetter state) {
+                               try {
+                                       backgroundFetchCallback.loaded(uri, result.getMimeType(), result.asByteArray());
+                               } catch (IOException e) {
+                                       backgroundFetchCallback.failed(uri);
+                               }
+                       }
+
+                       @Override
+                       public void onFailure(FetchException e, ClientGetter state) {
+                               backgroundFetchCallback.failed(uri);
+                       }
+
+                       @Override
+                       public void onResume(ClientContext context) throws ResumeFailedException {
+                               /* do nothing. */
+                       }
+
+                       @Override
+                       public RequestClient getRequestClient() {
+                               return imageLoader;
+                       }
+               };
+               FetchContext fetchContext = client.getFetchContext();
+               try {
+                       client.fetch(uri, 1048576, callback, fetchContext, RequestStarter.INTERACTIVE_PRIORITY_CLASS);
+               } catch (FetchException fe) {
+                       /* stupid exception that can not actually be thrown! */
+               }
+       }
+
+       public interface BackgroundFetchCallback {
+               void loaded(@Nonnull FreenetURI uri, @Nonnull String mimeType, @Nonnull byte[] data);
+               void failed(@Nonnull FreenetURI uri);
+       }
+
        /**
         * Inserts the image data of the given {@link TemporaryImage} and returns
         * the given insert token that can be used to add listeners or cancel the
index a0d8d0c..a8f9812 100644 (file)
@@ -1,5 +1,6 @@
 package net.pterodactylus.sone.core;
 
+import static freenet.client.FetchException.FetchExceptionMode.ALL_DATA_NOT_FOUND;
 import static freenet.keys.InsertableClientSSK.createRandom;
 import static freenet.node.RequestStarter.INTERACTIVE_PRIORITY_CLASS;
 import static freenet.node.RequestStarter.PREFETCH_PRIORITY_CLASS;
@@ -12,6 +13,7 @@ import static org.hamcrest.Matchers.nullValue;
 import static org.mockito.ArgumentCaptor.forClass;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyShort;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
@@ -19,6 +21,7 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.withSettings;
 
@@ -27,6 +30,7 @@ import java.net.MalformedURLException;
 import java.util.HashMap;
 
 import net.pterodactylus.sone.TestUtil;
+import net.pterodactylus.sone.core.FreenetInterface.BackgroundFetchCallback;
 import net.pterodactylus.sone.core.FreenetInterface.Callback;
 import net.pterodactylus.sone.core.FreenetInterface.Fetched;
 import net.pterodactylus.sone.core.FreenetInterface.InsertToken;
@@ -41,6 +45,7 @@ import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.data.TemporaryImage;
 
 import freenet.client.ClientMetadata;
+import freenet.client.FetchContext;
 import freenet.client.FetchException;
 import freenet.client.FetchException.FetchExceptionMode;
 import freenet.client.FetchResult;
@@ -49,6 +54,8 @@ import freenet.client.InsertBlock;
 import freenet.client.InsertContext;
 import freenet.client.InsertException;
 import freenet.client.InsertException.InsertExceptionMode;
+import freenet.client.async.ClientGetCallback;
+import freenet.client.async.ClientGetter;
 import freenet.client.async.ClientPutter;
 import freenet.client.async.USKCallback;
 import freenet.client.async.USKManager;
@@ -90,6 +97,18 @@ public class FreenetInterfaceTest {
        private final Image image = mock(Image.class);
        private InsertToken insertToken;
        private final Bucket bucket = mock(Bucket.class);
+       private final ArgumentCaptor<ClientGetCallback> clientGetCallback = forClass(ClientGetCallback.class);
+       private final FreenetURI uri = new FreenetURI("KSK@pgl.png");
+       private final FetchResult fetchResult = mock(FetchResult.class);
+       private final BackgroundFetchCallback backgroundFetchCallback = mock(BackgroundFetchCallback.class);
+
+       public FreenetInterfaceTest() throws MalformedURLException {
+       }
+
+       @Before
+       public void setupHighLevelSimpleClient() {
+               when(highLevelSimpleClient.getFetchContext()).thenReturn(mock(FetchContext.class));
+       }
 
        @Before
        public void setupFreenetInterface() {
@@ -141,7 +160,7 @@ public class FreenetInterfaceTest {
        @Test
        public void fetchReturnsNullOnFetchExceptions() throws MalformedURLException, FetchException {
                FreenetURI freenetUri = new FreenetURI("KSK@GPLv2.txt");
-               FetchException fetchException = new FetchException(FetchExceptionMode.ALL_DATA_NOT_FOUND);
+               FetchException fetchException = new FetchException(ALL_DATA_NOT_FOUND);
                when(highLevelSimpleClient.fetch(freenetUri)).thenThrow(fetchException);
                Fetched fetched = freenetInterface.fetchUri(freenetUri);
                assertThat(fetched, nullValue());
@@ -399,4 +418,43 @@ public class FreenetInterfaceTest {
                assertThat(insertTokenSupplier.apply(image), notNullValue());
        }
 
+       @Test
+       public void backgroundFetchCanBeStarted() throws Exception {
+               freenetInterface.startFetch(uri, backgroundFetchCallback);
+               verify(highLevelSimpleClient).fetch(eq(uri), anyLong(), any(ClientGetCallback.class), any(FetchContext.class), anyShort());
+       }
+
+       @Test
+       public void callbackOfBackgroundFetchIsNotifiedOnSuccess() throws Exception {
+               freenetInterface.startFetch(uri, backgroundFetchCallback);
+               verify(highLevelSimpleClient).fetch(eq(uri), anyLong(), clientGetCallback.capture(), any(FetchContext.class), anyShort());
+               when(fetchResult.getMimeType()).thenReturn("image/png");
+               when(fetchResult.asByteArray()).thenReturn(new byte[] { 1, 2, 3, 4, 5 });
+               clientGetCallback.getValue().onSuccess(fetchResult, mock(ClientGetter.class));
+               verify(backgroundFetchCallback).loaded(uri, "image/png", new byte[] { 1, 2, 3, 4, 5 });
+               verifyNoMoreInteractions(backgroundFetchCallback);
+       }
+
+       @Test
+       public void callbackOfBackgroundFetchIsNotifiedOnFailure() throws Exception {
+               freenetInterface.startFetch(uri, backgroundFetchCallback);
+               verify(highLevelSimpleClient).fetch(eq(uri), anyLong(), clientGetCallback.capture(), any(FetchContext.class), anyShort());
+               when(fetchResult.getMimeType()).thenReturn("image/png");
+               when(fetchResult.asByteArray()).thenReturn(new byte[] { 1, 2, 3, 4, 5 });
+               clientGetCallback.getValue().onFailure(new FetchException(ALL_DATA_NOT_FOUND), mock(ClientGetter.class));
+               verify(backgroundFetchCallback).failed(uri);
+               verifyNoMoreInteractions(backgroundFetchCallback);
+       }
+
+       @Test
+       public void callbackOfBackgroundFetchIsNotifiedAsFailureIfBucketCanNotBeLoaded() throws Exception {
+               freenetInterface.startFetch(uri, backgroundFetchCallback);
+               verify(highLevelSimpleClient).fetch(eq(uri), anyLong(), clientGetCallback.capture(), any(FetchContext.class), anyShort());
+               when(fetchResult.getMimeType()).thenReturn("image/png");
+               when(fetchResult.asByteArray()).thenThrow(IOException.class);
+               clientGetCallback.getValue().onSuccess(fetchResult, mock(ClientGetter.class));
+               verify(backgroundFetchCallback).failed(uri);
+               verifyNoMoreInteractions(backgroundFetchCallback);
+       }
+
 }