From 52829a244bc018045e60315be25db79d6863f116 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Fri, 25 Jun 2021 19:28:39 +0100 Subject: [PATCH] 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. --- .../org/qortal/api/resource/DataResource.java | 107 +++++++++++++++--- 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/qortal/api/resource/DataResource.java b/src/main/java/org/qortal/api/resource/DataResource.java index c7894989..326bc122 100644 --- a/src/main/java/org/qortal/api/resource/DataResource.java +++ b/src/main/java/org/qortal/api/resource/DataResource.java @@ -19,6 +19,7 @@ import org.qortal.repository.RepositoryManager; import org.qortal.settings.Settings; import org.qortal.storage.DataFile; import org.qortal.storage.DataFile.ValidationResult; +import org.qortal.storage.DataFileChunk; import org.qortal.utils.Base58; 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.Response; import java.io.File; -import java.io.IOException; import java.net.InetSocketAddress; import java.net.UnknownHostException; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.List; @@ -148,7 +146,7 @@ public class DataResource { } @GET - @Path("/file/frompeer") + @Path("/file/{hash}/frompeer/{peer}") @Operation( summary = "Request file from a given peer, using supplied base58 encoded SHA256 digest string", 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}) - public Response getFileFromPeer(@QueryParam("base58Digest") String base58Digest, - @QueryParam("peer") String targetPeerAddress) { - - try (final Repository repository = RepositoryManager.getRepository()) { - + public Response getFileFromPeer(@PathParam("hash") String base58Digest, + @PathParam("peer") String targetPeerAddress) { + try { if (base58Digest == null) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA); } @@ -179,15 +175,92 @@ public class DataResource { // Try to resolve passed address to make things easier PeerAddress peerAddress = PeerAddress.fromString(targetPeerAddress); InetSocketAddress resolvedAddress = peerAddress.toSocketAddress(); - List peers = Network.getInstance().getHandshakedPeers(); Peer targetPeer = peers.stream().filter(peer -> peer.getResolvedAddress().toString().contains(resolvedAddress.toString())).findFirst().orElse(null); if (targetPeer == null) { LOGGER.info("Peer {} isn't connected", targetPeerAddress); - throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); + 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); + } + } + + @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 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); if (dataFile.exists()) { LOGGER.info("Data file {} already exists but we'll request it anyway", dataFile); @@ -204,25 +277,23 @@ public class DataResource { Message message = targetPeer.getResponse(getDataFileMessage); 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 - throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FILE_NOT_FOUND); + return false; } DataFileMessage dataFileMessage = (DataFileMessage) message; dataFile = dataFileMessage.getDataFile(); if (dataFile == null || !dataFile.exists()) { - throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FILE_NOT_FOUND); + return false; } - - return Response.ok(String.format("Received file %s, size %d bytes", dataFileMessage.getDataFile(), dataFileMessage.getDataFile().size())).build(); + LOGGER.info(String.format("Received file %s, size %d bytes", dataFileMessage.getDataFile(), dataFileMessage.getDataFile().size())); + return true; } catch (ApiException e) { throw e; } catch (DataException | InterruptedException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); - } catch (UnknownHostException e) { - throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); } }