Follow redirects in ClientGet feature/quelaton-client
authorDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Mon, 2 Nov 2015 20:55:29 +0000 (21:55 +0100)
committerDavid ‘Bombe’ Roden <bombe@freenetproject.org>
Mon, 2 Nov 2015 20:55:29 +0000 (21:55 +0100)
src/main/java/net/pterodactylus/fcp/quelaton/ClientGetCommand.java
src/main/java/net/pterodactylus/fcp/quelaton/ClientGetCommandImpl.java
src/main/java/net/pterodactylus/fcp/quelaton/FcpDialog.java
src/test/java/net/pterodactylus/fcp/quelaton/DefaultFcpClientTest.java

index 01f88e9..385506f 100644 (file)
@@ -2,6 +2,7 @@ package net.pterodactylus.fcp.quelaton;
 
 import java.io.InputStream;
 import java.util.Optional;
+import java.util.function.Consumer;
 
 import net.pterodactylus.fcp.Priority;
 
@@ -12,6 +13,7 @@ import net.pterodactylus.fcp.Priority;
  */
 public interface ClientGetCommand {
 
+       ClientGetCommand onRedirect(Consumer<String> onRedirect);
        ClientGetCommand ignoreDataStore();
        ClientGetCommand dataStoreOnly();
        ClientGetCommand maxSize(long maxSize);
index 7908f5c..e60fed7 100644 (file)
@@ -2,9 +2,12 @@ package net.pterodactylus.fcp.quelaton;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 import net.pterodactylus.fcp.AllData;
@@ -27,6 +30,7 @@ class ClientGetCommandImpl implements ClientGetCommand {
        private final ListeningExecutorService threadPool;
        private final ConnectionSupplier connectionSupplier;
        private final Supplier<String> identifierGenerator;
+       private final List<Consumer<String>> onRedirects = new ArrayList<>();
 
        private boolean ignoreDataStore;
        private boolean dataStoreOnly;
@@ -42,6 +46,12 @@ class ClientGetCommandImpl implements ClientGetCommand {
        }
 
        @Override
+       public ClientGetCommand onRedirect(Consumer<String> onRedirect) {
+               onRedirects.add(onRedirect);
+               return this;
+       }
+
+       @Override
        public ClientGetCommand ignoreDataStore() {
                ignoreDataStore = true;
                return this;
@@ -83,14 +93,13 @@ class ClientGetCommandImpl implements ClientGetCommand {
        }
 
        private Optional<Data> execute(String uri) throws InterruptedException, ExecutionException, IOException {
-               ClientGet clientGet = createClientGetCommand(uri);
+               ClientGet clientGet = createClientGetCommand(identifierGenerator.get(), uri);
                try (ClientGetDialog clientGetDialog = new ClientGetDialog()) {
                        return clientGetDialog.send(clientGet).get();
                }
        }
 
-       private ClientGet createClientGetCommand(String uri) {
-               String identifier = identifierGenerator.get();
+       private ClientGet createClientGetCommand(String identifier, String uri) {
                ClientGet clientGet = new ClientGet(uri, identifier, ReturnType.direct);
                if (ignoreDataStore) {
                        clientGet.setIgnoreDataStore(true);
@@ -116,7 +125,8 @@ class ClientGetCommandImpl implements ClientGetCommand {
        private class ClientGetDialog extends FcpDialog<Optional<Data>> {
 
                public ClientGetDialog() throws IOException {
-                       super(ClientGetCommandImpl.this.threadPool, ClientGetCommandImpl.this.connectionSupplier.get(), Optional.<Data>empty());
+                       super(ClientGetCommandImpl.this.threadPool, ClientGetCommandImpl.this.connectionSupplier.get(),
+                               Optional.<Data>empty());
                }
 
                @Override
@@ -155,7 +165,12 @@ class ClientGetCommandImpl implements ClientGetCommand {
 
                @Override
                protected void consumeGetFailed(GetFailed getFailed) {
-                       finish();
+                       if (getFailed.getCode() == 27) {
+                               onRedirects.forEach(onRedirect -> onRedirect.accept(getFailed.getRedirectURI()));
+                               sendMessage(createClientGetCommand(getIdentifier(), getFailed.getRedirectURI()));
+                       } else {
+                               finish();
+                       }
                }
 
        }
index 5b030bd..f2b71fd 100644 (file)
@@ -85,6 +85,10 @@ public abstract class FcpDialog<R> implements AutoCloseable, FcpListener {
                this.identifier.set(identifier);
        }
 
+       protected String getIdentifier() {
+               return identifier.get();
+       }
+
        public final boolean isFinished() {
                return finished.get();
        }
index 0a39451..61a7d0a 100644 (file)
@@ -1299,6 +1299,30 @@ public class DefaultFcpClientTest {
                        connectAndAssert(() -> matchesFcpMessage("ClientGet", "URI=KSK@foo.txt", "Global=true"));
                }
 
+               @Test
+               public void clientGetFollowsRedirect() throws InterruptedException, ExecutionException, IOException {
+                   Future<Optional<Data>> data = fcpClient.clientGet().uri("USK@foo/bar").execute();
+                       connectAndAssert(() -> matchesFcpMessage("ClientGet", "URI=USK@foo/bar"));
+                       replyWithRedirect("USK@foo/baz");
+                       readMessage(() -> matchesFcpMessage("ClientGet", "URI=USK@foo/baz"));
+                       replyWithAllData(identifier, "Hello", "text/plain;charset=utf-8");
+                       verifyData(data.get());
+               }
+
+               @Test
+               public void clientGetNotifiesListenersOnRedirect() throws IOException, ExecutionException, InterruptedException {
+                       List<String> redirects = new ArrayList<>();
+                       Future<Optional<Data>> data = fcpClient.clientGet().onRedirect(redirects::add).uri("USK@foo/bar").execute();
+                       connectAndAssert(() -> matchesFcpMessage("ClientGet", "URI=USK@foo/bar"));
+                       replyWithRedirect("USK@foo/baz");
+                       readMessage(() -> matchesFcpMessage("ClientGet", "URI=USK@foo/baz"));
+                       replyWithRedirect("USK@foo/quux");
+                       readMessage(() -> matchesFcpMessage("ClientGet", "URI=USK@foo/quux"));
+                       replyWithAllData(identifier, "Hello", "text/plain;charset=utf-8");
+                       verifyData(data.get());
+                       assertThat(redirects, contains("USK@foo/baz", "USK@foo/quux"));
+               }
+
                private void replyWithGetFailed(String identifier) throws IOException {
                        fcpServer.writeLine(
                                "GetFailed",
@@ -1308,6 +1332,16 @@ public class DefaultFcpClientTest {
                        );
                }
 
+               private void replyWithRedirect(String newUri) throws IOException {
+                       fcpServer.writeLine(
+                               "GetFailed",
+                               "Identifier=" + identifier,
+                               "Code=27",
+                               "RedirectURI=" + newUri,
+                               "EndMessage"
+                       );
+               }
+
                private void replyWithAllData(String identifier, String text, String contentType) throws IOException {
                        fcpServer.writeLine(
                                "AllData",