More work on APIs to request files from peers. I won't spend too long making these perfect as they are mostly a temporary measure.

This commit is contained in:
CalDescent 2021-06-25 19:28:39 +01:00
parent 71c247fe56
commit 52829a244b

View File

@ -19,6 +19,7 @@ import org.qortal.repository.RepositoryManager;
import org.qortal.settings.Settings; import org.qortal.settings.Settings;
import org.qortal.storage.DataFile; import org.qortal.storage.DataFile;
import org.qortal.storage.DataFile.ValidationResult; import org.qortal.storage.DataFile.ValidationResult;
import org.qortal.storage.DataFileChunk;
import org.qortal.utils.Base58; import org.qortal.utils.Base58;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -27,11 +28,8 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List; import java.util.List;
@ -148,7 +146,7 @@ public class DataResource {
} }
@GET @GET
@Path("/file/frompeer") @Path("/file/{hash}/frompeer/{peer}")
@Operation( @Operation(
summary = "Request file from a given peer, using supplied base58 encoded SHA256 digest string", summary = "Request file from a given peer, using supplied base58 encoded SHA256 digest string",
responses = { responses = {
@ -164,11 +162,9 @@ public class DataResource {
} }
) )
@ApiErrors({ApiError.REPOSITORY_ISSUE, ApiError.INVALID_DATA, ApiError.INVALID_CRITERIA, ApiError.FILE_NOT_FOUND, ApiError.NO_REPLY}) @ApiErrors({ApiError.REPOSITORY_ISSUE, ApiError.INVALID_DATA, ApiError.INVALID_CRITERIA, ApiError.FILE_NOT_FOUND, ApiError.NO_REPLY})
public Response getFileFromPeer(@QueryParam("base58Digest") String base58Digest, public Response getFileFromPeer(@PathParam("hash") String base58Digest,
@QueryParam("peer") String targetPeerAddress) { @PathParam("peer") String targetPeerAddress) {
try {
try (final Repository repository = RepositoryManager.getRepository()) {
if (base58Digest == null) { if (base58Digest == null) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
} }
@ -179,14 +175,91 @@ public class DataResource {
// Try to resolve passed address to make things easier // Try to resolve passed address to make things easier
PeerAddress peerAddress = PeerAddress.fromString(targetPeerAddress); PeerAddress peerAddress = PeerAddress.fromString(targetPeerAddress);
InetSocketAddress resolvedAddress = peerAddress.toSocketAddress(); InetSocketAddress resolvedAddress = peerAddress.toSocketAddress();
List<Peer> peers = Network.getInstance().getHandshakedPeers(); List<Peer> peers = Network.getInstance().getHandshakedPeers();
Peer targetPeer = peers.stream().filter(peer -> peer.getResolvedAddress().toString().contains(resolvedAddress.toString())).findFirst().orElse(null); Peer targetPeer = peers.stream().filter(peer -> peer.getResolvedAddress().toString().contains(resolvedAddress.toString())).findFirst().orElse(null);
if (targetPeer == null) { if (targetPeer == null) {
LOGGER.info("Peer {} isn't connected", targetPeerAddress); LOGGER.info("Peer {} isn't connected", targetPeerAddress);
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
}
boolean success = this.requestFile(base58Digest, targetPeer);
if (success) {
return Response.ok("true").build();
}
return Response.ok("false").build();
} catch (UnknownHostException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA);
} }
}
@POST
@Path("/files/frompeer/{peer}")
@Operation(
summary = "Request multiple files from a given peer, using supplied comma separated base58 encoded SHA256 digest strings",
requestBody = @RequestBody(
required = true,
content = @Content(
mediaType = MediaType.TEXT_PLAIN,
schema = @Schema(
type = "string", example = "FZdHKgF5CbN2tKihvop5Ts9vmWmA9ZyyPY6bC1zivjy4,FZdHKgF5CbN2tKihvop5Ts9vmWmA9ZyyPY6bC1zivjy4"
)
)
),
responses = {
@ApiResponse(
description = "true if retrieved, false if not",
content = @Content(
mediaType = MediaType.TEXT_PLAIN,
schema = @Schema(
type = "string"
)
)
)
}
)
@ApiErrors({ApiError.REPOSITORY_ISSUE, ApiError.INVALID_DATA, ApiError.INVALID_CRITERIA, ApiError.FILE_NOT_FOUND, ApiError.NO_REPLY})
public Response getFilesFromPeer(String files, @PathParam("peer") String targetPeerAddress) {
try {
if (targetPeerAddress == null) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
}
// Try to resolve passed address to make things easier
PeerAddress peerAddress = PeerAddress.fromString(targetPeerAddress);
InetSocketAddress resolvedAddress = peerAddress.toSocketAddress();
List<Peer> peers = Network.getInstance().getHandshakedPeers();
Peer targetPeer = peers.stream().filter(peer -> peer.getResolvedAddress().toString().contains(resolvedAddress.toString())).findFirst().orElse(null);
for (Peer peer : peers) {
LOGGER.info("peer: {}", peer);
}
if (targetPeer == null) {
LOGGER.info("Peer {} isn't connected", targetPeerAddress);
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
}
String base58DigestList[] = files.split(",");
for (String base58Digest : base58DigestList) {
if (base58Digest != null) {
boolean success = this.requestFile(base58Digest, targetPeer);
if (!success) {
LOGGER.info("Failed to request file {} from peer {}", base58Digest, targetPeerAddress);
}
}
}
return Response.ok("true").build();
} catch (UnknownHostException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA);
}
}
private boolean requestFile(String base58Digest, Peer targetPeer) {
try (final Repository repository = RepositoryManager.getRepository()) {
DataFile dataFile = DataFile.fromBase58Digest(base58Digest); DataFile dataFile = DataFile.fromBase58Digest(base58Digest);
if (dataFile.exists()) { if (dataFile.exists()) {
@ -204,25 +277,23 @@ public class DataResource {
Message message = targetPeer.getResponse(getDataFileMessage); Message message = targetPeer.getResponse(getDataFileMessage);
if (message == null) { if (message == null) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.NO_REPLY); return false;
} }
else if (message.getType() == Message.MessageType.BLOCK_SUMMARIES) { // TODO: use dedicated message type here else if (message.getType() == Message.MessageType.BLOCK_SUMMARIES) { // TODO: use dedicated message type here
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FILE_NOT_FOUND); return false;
} }
DataFileMessage dataFileMessage = (DataFileMessage) message; DataFileMessage dataFileMessage = (DataFileMessage) message;
dataFile = dataFileMessage.getDataFile(); dataFile = dataFileMessage.getDataFile();
if (dataFile == null || !dataFile.exists()) { if (dataFile == null || !dataFile.exists()) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FILE_NOT_FOUND); return false;
} }
LOGGER.info(String.format("Received file %s, size %d bytes", dataFileMessage.getDataFile(), dataFileMessage.getDataFile().size()));
return Response.ok(String.format("Received file %s, size %d bytes", dataFileMessage.getDataFile(), dataFileMessage.getDataFile().size())).build(); return true;
} catch (ApiException e) { } catch (ApiException e) {
throw e; throw e;
} catch (DataException | InterruptedException e) { } catch (DataException | InterruptedException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
} catch (UnknownHostException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA);
} }
} }