X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Ffcp%2Fhighlevel%2FFcpClient.java;h=6413dc2787d08dc8dfd36d8b9348883804e8f3ff;hb=a30d521e1add957b2ddfee455bc6e061efbf44b7;hp=73998185b61cc4a0577d99a09f57dab99ec644c0;hpb=9eefde565838c38a0eedde679936e58acfa25577;p=jFCPlib.git diff --git a/src/main/java/net/pterodactylus/fcp/highlevel/FcpClient.java b/src/main/java/net/pterodactylus/fcp/highlevel/FcpClient.java index 7399818..6413dc2 100644 --- a/src/main/java/net/pterodactylus/fcp/highlevel/FcpClient.java +++ b/src/main/java/net/pterodactylus/fcp/highlevel/FcpClient.java @@ -1,9 +1,9 @@ /* - * jFCPlib - FcpClient.java - Copyright © 2009 David Roden + * jFCPlib - FcpClient.java - Copyright © 2009–2016 David Roden * - * This program is free software; you can redistribute it and/or modify + * 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 2 of the License, or + * 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, @@ -12,12 +12,14 @@ * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program. If not, see . */ package net.pterodactylus.fcp.highlevel; +import static com.google.common.collect.FluentIterable.from; + +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; @@ -28,11 +30,14 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; import net.pterodactylus.fcp.AddPeer; +import net.pterodactylus.fcp.AllData; +import net.pterodactylus.fcp.ClientGet; import net.pterodactylus.fcp.ClientHello; import net.pterodactylus.fcp.CloseConnectionDuplicateClientName; import net.pterodactylus.fcp.DataFound; @@ -65,9 +70,8 @@ import net.pterodactylus.fcp.RemovePeer; import net.pterodactylus.fcp.SSKKeypair; import net.pterodactylus.fcp.SimpleProgress; import net.pterodactylus.fcp.WatchGlobal; -import net.pterodactylus.util.filter.Filter; -import net.pterodactylus.util.filter.Filters; -import net.pterodactylus.util.thread.ObjectWrapper; + +import com.google.common.base.Predicate; /** * High-level FCP client that hides the details of the underlying FCP @@ -75,7 +79,7 @@ import net.pterodactylus.util.thread.ObjectWrapper; * * @author David ‘Bombe’ Roden <bombe@freenetproject.org> */ -public class FcpClient { +public class FcpClient implements Closeable { /** Object used for synchronization. */ private final Object syncObject = new Object(); @@ -92,6 +96,9 @@ public class FcpClient { /** Whether the client is currently connected. */ private volatile boolean connected; + /** The listener for “connection closed” events. */ + private FcpListener connectionClosedListener; + /** * Creates an FCP client with the given name. * @@ -147,8 +154,33 @@ public class FcpClient { * The Freenet node’s FCP port */ public FcpClient(InetAddress host, int port) { - fcpConnection = new FcpConnection(host, port); - fcpConnection.addFcpListener(new FcpAdapter() { + this(new FcpConnection(host, port), false); + } + + /** + * Creates a new high-level FCP client that will use the given connection. + * This constructor will assume that the FCP connection is already + * connected. + * + * @param fcpConnection + * The FCP connection to use + */ + public FcpClient(FcpConnection fcpConnection) { + this(fcpConnection, true); + } + + /** + * Creates a new high-level FCP client that will use the given connection. + * + * @param fcpConnection + * The FCP connection to use + * @param connected + * The initial status of the FCP connection + */ + public FcpClient(FcpConnection fcpConnection, boolean connected) { + this.fcpConnection = fcpConnection; + this.connected = connected; + connectionClosedListener = new FcpAdapter() { /** * {@inheritDoc} @@ -156,10 +188,11 @@ public class FcpClient { @Override @SuppressWarnings("synthetic-access") public void connectionClosed(FcpConnection fcpConnection, Throwable throwable) { - connected = false; + FcpClient.this.connected = false; fcpClientListenerManager.fireFcpClientDisconnected(); } - }); + }; + fcpConnection.addFcpListener(connectionClosedListener); } // @@ -274,6 +307,88 @@ public class FcpClient { } /** + * Returns the file with the given URI. The retrieved data will be run + * through Freenet’s content filter. + * + * @param uri + * The URI to get + * @return The result of the get request + * @throws IOException + * if an I/O error occurs + * @throws FcpException + * if an FCP error occurs + */ + public GetResult getURI(final String uri) throws IOException, FcpException { + return getURI(uri, true); + } + + /** + * Returns the file with the given URI. + * + * @param uri + * The URI to get + * @param filterData + * {@code true} to filter the retrieved data, {@code false} + * otherwise + * @return The result of the get request + * @throws IOException + * if an I/O error occurs + * @throws FcpException + * if an FCP error occurs + */ + public GetResult getURI(final String uri, final boolean filterData) throws IOException, FcpException { + checkConnected(true); + final GetResult getResult = new GetResult(); + new ExtendedFcpAdapter() { + + @SuppressWarnings("synthetic-access") + private final String identifier = createIdentifier("client-get"); + + @Override + @SuppressWarnings("synthetic-access") + public void run() throws IOException { + ClientGet clientGet = new ClientGet(uri, identifier); + clientGet.setFilterData(filterData); + fcpConnection.sendMessage(clientGet); + } + + @Override + public void receivedGetFailed(FcpConnection fcpConnection, GetFailed getFailed) { + if (!getFailed.getIdentifier().equals(identifier)) { + return; + } + if ((getFailed.getCode() == 27) || (getFailed.getCode() == 24)) { + /* redirect! */ + String newUri = getFailed.getRedirectURI(); + getResult.realUri(newUri); + try { + ClientGet clientGet = new ClientGet(newUri, identifier); + clientGet.setFilterData(filterData); + fcpConnection.sendMessage(clientGet); + } catch (IOException ioe1) { + getResult.success(false).exception(ioe1); + completionLatch.countDown(); + } + } else { + getResult.success(false).errorCode(getFailed.getCode()); + completionLatch.countDown(); + } + } + + @Override + public void receivedAllData(FcpConnection fcpConnection, AllData allData) { + if (!allData.getIdentifier().equals(identifier)) { + return; + } + getResult.success(true).contentType(allData.getContentType()).contentLength(allData.getDataLength()).inputStream(allData.getPayloadInputStream()); + completionLatch.countDown(); + } + + }.execute(); + return getResult; + } + + /** * Disconnects the FCP client. */ public void disconnect() { @@ -284,6 +399,14 @@ public class FcpClient { } /** + * {@inheritDoc} + */ + @Override + public void close() { + disconnect(); + } + + /** * Returns whether this client is currently connected. * * @return {@code true} if the client is currently connected, {@code false} @@ -293,6 +416,13 @@ public class FcpClient { return connected; } + /** + * Detaches this client from its underlying FCP connection. + */ + public void detach() { + fcpConnection.removeFcpListener(connectionClosedListener); + } + // // PEER MANAGEMENT // @@ -466,8 +596,8 @@ public class FcpClient { /** * Adds a peer, reading the noderef of the peer from the given file. - * Note: the file to read the noderef from has to reside on - * the same machine as the node! + * Note: the file to read the noderef from has to reside + * on the same machine as the node! * * @param file * The name of the file containing the peer’s noderef @@ -606,7 +736,7 @@ public class FcpClient { * if an FCP error occurs */ public PeerNote getPeerNote(final Peer peer) throws IOException, FcpException { - final ObjectWrapper objectWrapper = new ObjectWrapper(); + final AtomicReference objectWrapper = new AtomicReference(); new ExtendedFcpAdapter() { /** @@ -692,7 +822,7 @@ public class FcpClient { * if an FCP error occurs */ public SSKKeypair generateKeyPair() throws IOException, FcpException { - final ObjectWrapper sskKeypairWrapper = new ObjectWrapper(); + final AtomicReference sskKeypairWrapper = new AtomicReference(); new ExtendedFcpAdapter() { /** @@ -734,15 +864,12 @@ public class FcpClient { * if an FCP error occurs */ public Collection getGetRequests(final boolean global) throws IOException, FcpException { - return Filters.filteredCollection(getRequests(global), new Filter() { - - /** - * {@inheritDoc} - */ - public boolean filterObject(Request request) { + return from(getRequests(global)).filter(new Predicate() { + @Override + public boolean apply(Request request) { return request instanceof GetRequest; } - }); + }).toList(); } /** @@ -759,15 +886,12 @@ public class FcpClient { * if an FCP error occurs */ public Collection getPutRequests(final boolean global) throws IOException, FcpException { - return Filters.filteredCollection(getRequests(global), new Filter() { - - /** - * {@inheritDoc} - */ - public boolean filterObject(Request request) { + return from(getRequests(global)).filter(new Predicate() { + @Override + public boolean apply(Request request) { return request instanceof PutRequest; } - }); + }).toList(); } /** @@ -775,8 +899,8 @@ public class FcpClient { * * @param global * true to return requests from the global queue, - * false to only show requests from the client-local - * queue + * false to only show requests from the + * client-local queue * @return All requests * @throws IOException * if an I/O error occurs @@ -981,7 +1105,7 @@ public class FcpClient { * if an I/O error occurs */ public NodeData getNodeInformation(final Boolean giveOpennetRef, final Boolean withPrivate, final Boolean withVolatile) throws IOException, FcpException { - final ObjectWrapper nodeDataWrapper = new ObjectWrapper(); + final AtomicReference nodeDataWrapper = new AtomicReference(); new ExtendedFcpAdapter() { @Override