import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
import net.pterodactylus.fcp.AllData;
import net.pterodactylus.fcp.ClientHello;
import net.pterodactylus.fcp.FcpListener;
import net.pterodactylus.fcp.FcpMessage;
import net.pterodactylus.fcp.FinishedCompression;
+import net.pterodactylus.fcp.GenerateSSK;
import net.pterodactylus.fcp.GetFailed;
import net.pterodactylus.fcp.IdentifierCollision;
+import net.pterodactylus.fcp.ListPeers;
import net.pterodactylus.fcp.NodeData;
import net.pterodactylus.fcp.NodeHello;
import net.pterodactylus.fcp.Peer;
/** The callback for {@link #connect()}. */
private HighLevelCallback<ConnectResult> connectCallback;
+ /** Mapping from request identifiers to callbacks. */
+ private Map<String, HighLevelCallback<KeyGenerationResult>> keyGenerationCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<KeyGenerationResult>>());
+
+ /** Mapping from request identifier to peer list callbacks. */
+ private Map<String, HighLevelCallback<PeerListResult>> peerListCallbacks = Collections.synchronizedMap(new HashMap<String, HighLevelCallback<PeerListResult>>());
+
/**
* Creates a new high-level client that connects to a node on
* <code>localhost</code>.
fcpConnection = new FcpConnection(address, port);
fcpConnection.addFcpListener(highLevelClientFcpListener);
ClientHello clientHello = new ClientHello(clientName);
- connectCallback = new HighLevelCallback<ConnectResult>();
+ connectCallback = new HighLevelCallback<ConnectResult>(new ConnectResult());
fcpConnection.sendMessage(clientHello);
return connectCallback;
}
}
/**
+ * Generates a new SSK keypair.
+ *
+ * @return A callback with the keypair
+ * @throws IOException
+ * if an I/O error occurs communicating with the node
+ */
+ public HighLevelCallback<KeyGenerationResult> generateKey() throws IOException {
+ String identifier = generateIdentifier("generateSSK");
+ GenerateSSK generateSSK = new GenerateSSK(identifier);
+ HighLevelCallback<KeyGenerationResult> keyGenerationCallback = new HighLevelCallback<KeyGenerationResult>(new KeyGenerationResult());
+ keyGenerationCallbacks.put(identifier, keyGenerationCallback);
+ fcpConnection.sendMessage(generateSSK);
+ return keyGenerationCallback;
+ }
+
+ /**
+ * Gets a list of all peers from the node.
+ *
+ * @return A callback with the peer list
+ * @throws IOException
+ * if an I/O error occurs with the node
+ */
+ public HighLevelCallback<PeerListResult> getPeers() throws IOException {
+ String identifier = generateIdentifier("listPeers");
+ ListPeers listPeers = new ListPeers(identifier, true, true);
+ HighLevelCallback<PeerListResult> peerListCallback = new HighLevelCallback<PeerListResult>(new PeerListResult());
+ peerListCallbacks.put(identifier, peerListCallback);
+ fcpConnection.sendMessage(listPeers);
+ return peerListCallback;
+ }
+
+ /**
+ * Generates an identifier for the given function.
+ *
+ * @param function
+ * The name of the function
+ * @return An identifier
+ */
+ private String generateIdentifier(String function) {
+ return "jFCPlib-" + function + "-" + System.currentTimeMillis();
+ }
+
+ /**
* FCP listener for {@link HighLevelClient}.
*
* @author David ‘Bombe’ Roden <bombe@freenetproject.org>
HighLevelClientFcpListener() {
}
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Searches all callback collections for a callback with the given
+ * identifier and cancels it.
+ *
+ * @param identifier
+ * The identifier to search for, or <code>null</code> to
+ * cancel all pending requests
+ */
+ @SuppressWarnings("synthetic-access")
+ private void cancelIdentifier(String identifier) {
+ synchronized (syncObject) {
+ if (connectCallback != null) {
+ connectCallback.getIntermediaryResult().setFailed(true);
+ connectCallback.setDone();
+ connectCallback = null;
+ }
+ }
+ if (identifier == null) {
+ /* key generation callbacks */
+ for (Entry<String, HighLevelCallback<KeyGenerationResult>> keyGenerationEntry: keyGenerationCallbacks.entrySet()) {
+ keyGenerationEntry.getValue().getIntermediaryResult().setFailed(true);
+ keyGenerationEntry.getValue().setDone();
+ }
+ keyGenerationCallbacks.clear();
+ /* peer list callbacks. */
+ for (Entry<String, HighLevelCallback<PeerListResult>> peerListEntry: peerListCallbacks.entrySet()) {
+ peerListEntry.getValue().getIntermediaryResult().setFailed(true);
+ peerListEntry.getValue().setDone();
+ }
+ peerListCallbacks.clear();
+ } else {
+ HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(identifier);
+ if (keyGenerationCallback != null) {
+ keyGenerationCallback.getIntermediaryResult().setFailed(true);
+ keyGenerationCallback.setDone();
+ return;
+ }
+ HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
+ if (peerListCallback != null) {
+ peerListCallback.getIntermediaryResult().setFailed(true);
+ peerListCallback.setDone();
+ return;
+ }
+ }
+ }
+
+ //
+ // INTERFACE FcpListener
+ //
+
/**
* @see net.pterodactylus.fcp.FcpListener#connectionClosed(net.pterodactylus.fcp.FcpConnection)
*/
+ @SuppressWarnings("synthetic-access")
public void connectionClosed(FcpConnection fcpConnection) {
+ if (fcpConnection != HighLevelClient.this.fcpConnection) {
+ return;
+ }
+ cancelIdentifier(null);
}
/**
* @see net.pterodactylus.fcp.FcpListener#receivedEndListPeers(net.pterodactylus.fcp.FcpConnection,
* net.pterodactylus.fcp.EndListPeers)
*/
+ @SuppressWarnings("synthetic-access")
public void receivedEndListPeers(FcpConnection fcpConnection, EndListPeers endListPeers) {
+ if (fcpConnection != HighLevelClient.this.fcpConnection) {
+ return;
+ }
+ String identifier = endListPeers.getIdentifier();
+ HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.remove(identifier);
+ if (peerListCallback == null) {
+ return;
+ }
+ peerListCallback.setDone();
}
/**
if (fcpConnection != HighLevelClient.this.fcpConnection) {
return;
}
- ConnectResult connectResult = new ConnectResult();
-
synchronized (syncObject) {
- connectCallback.setResult(connectResult);
+ connectCallback.getIntermediaryResult().setFailed(false);
+ connectCallback.setDone();
+ connectCallback = null;
}
}
* @see net.pterodactylus.fcp.FcpListener#receivedPeer(net.pterodactylus.fcp.FcpConnection,
* net.pterodactylus.fcp.Peer)
*/
+ @SuppressWarnings("synthetic-access")
public void receivedPeer(FcpConnection fcpConnection, Peer peer) {
+ if (fcpConnection != HighLevelClient.this.fcpConnection) {
+ return;
+ }
+ String identifier = peer.getIdentifier();
+ HighLevelCallback<PeerListResult> peerListCallback = peerListCallbacks.get(identifier);
+ if (peerListCallback == null) {
+ return;
+ }
+ peerListCallback.getIntermediaryResult().addPeer(peer);
}
/**
* @see net.pterodactylus.fcp.FcpListener#receivedProtocolError(net.pterodactylus.fcp.FcpConnection,
* net.pterodactylus.fcp.ProtocolError)
*/
+ @SuppressWarnings("synthetic-access")
public void receivedProtocolError(FcpConnection fcpConnection, ProtocolError protocolError) {
+ if (fcpConnection != HighLevelClient.this.fcpConnection) {
+ return;
+ }
+ String identifier = protocolError.getIdentifier();
+ if (identifier == null) {
+ return;
+ }
+ cancelIdentifier(identifier);
}
/**
* @see net.pterodactylus.fcp.FcpListener#receivedSSKKeypair(net.pterodactylus.fcp.FcpConnection,
* net.pterodactylus.fcp.SSKKeypair)
*/
+ @SuppressWarnings("synthetic-access")
public void receivedSSKKeypair(FcpConnection fcpConnection, SSKKeypair sskKeypair) {
+ if (fcpConnection != HighLevelClient.this.fcpConnection) {
+ return;
+ }
+ HighLevelCallback<KeyGenerationResult> keyGenerationCallback = keyGenerationCallbacks.remove(sskKeypair.getIdentifier());
+ if (keyGenerationCallback == null) {
+ return;
+ }
+ KeyGenerationResult keyGenerationResult = keyGenerationCallback.getIntermediaryResult();
+ keyGenerationResult.setInsertURI(sskKeypair.getInsertURI());
+ keyGenerationResult.setRequestURI(sskKeypair.getRequestURI());
+ keyGenerationCallback.setDone();
}
/**