forked from Qortal/qortal
Removed various /arbitrary API endpoints that were only really useful at the start of the data storage project.
This commit is contained in:
parent
e6cc4a1180
commit
c724ea9f69
@ -168,58 +168,6 @@ public class ArbitraryResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("/raw/{signature}")
|
|
||||||
@Operation(
|
|
||||||
summary = "Fetch raw data associated with passed transaction signature",
|
|
||||||
responses = {
|
|
||||||
@ApiResponse(
|
|
||||||
description = "raw data",
|
|
||||||
content = @Content(
|
|
||||||
schema = @Schema(type = "string", format = "byte"),
|
|
||||||
mediaType = MediaType.APPLICATION_OCTET_STREAM
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@ApiErrors({
|
|
||||||
ApiError.INVALID_SIGNATURE, ApiError.REPOSITORY_ISSUE, ApiError.TRANSACTION_INVALID
|
|
||||||
})
|
|
||||||
public byte[] fetchRawData(@PathParam("signature") String signature58) {
|
|
||||||
// Decode signature
|
|
||||||
byte[] signature;
|
|
||||||
try {
|
|
||||||
signature = Base58.decode(signature58);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
|
||||||
TransactionData transactionData = repository.getTransactionRepository().fromSignature(signature);
|
|
||||||
|
|
||||||
if (transactionData == null || transactionData.getType() != TransactionType.ARBITRARY)
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_SIGNATURE);
|
|
||||||
|
|
||||||
ArbitraryTransactionData arbitraryTxData = (ArbitraryTransactionData) transactionData;
|
|
||||||
|
|
||||||
// We're really expecting to only fetch the data's hash from repository
|
|
||||||
if (arbitraryTxData.getDataType() != DataType.DATA_HASH)
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSACTION_INVALID);
|
|
||||||
|
|
||||||
ArbitraryTransaction arbitraryTx = new ArbitraryTransaction(repository, arbitraryTxData);
|
|
||||||
|
|
||||||
// For now, we only allow locally stored data
|
|
||||||
if (!arbitraryTx.isDataLocal())
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSACTION_INVALID);
|
|
||||||
|
|
||||||
return arbitraryTx.fetchData();
|
|
||||||
} catch (ApiException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (DataException e) {
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Build raw, unsigned, ARBITRARY transaction",
|
summary = "Build raw, unsigned, ARBITRARY transaction",
|
||||||
@ -619,247 +567,4 @@ public class ArbitraryResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@DELETE
|
|
||||||
@Path("/file")
|
|
||||||
@Operation(
|
|
||||||
summary = "Delete file using supplied base58 encoded SHA256 digest string",
|
|
||||||
requestBody = @RequestBody(
|
|
||||||
required = true,
|
|
||||||
content = @Content(
|
|
||||||
mediaType = MediaType.TEXT_PLAIN,
|
|
||||||
schema = @Schema(
|
|
||||||
type = "string", example = "FZdHKgF5CbN2tKihvop5Ts9vmWmA9ZyyPY6bC1zivjy4"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
responses = {
|
|
||||||
@ApiResponse(
|
|
||||||
description = "true if deleted, false if not",
|
|
||||||
content = @Content(
|
|
||||||
mediaType = MediaType.TEXT_PLAIN,
|
|
||||||
schema = @Schema(
|
|
||||||
type = "string"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
public String deleteFile(String hash58) {
|
|
||||||
Security.checkApiCallAllowed(request);
|
|
||||||
|
|
||||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash58(hash58);
|
|
||||||
if (arbitraryDataFile.delete()) {
|
|
||||||
return "true";
|
|
||||||
}
|
|
||||||
return "false";
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("/file/{hash}/frompeer/{peer}")
|
|
||||||
@Operation(
|
|
||||||
summary = "Request file from a given peer, using supplied base58 encoded SHA256 hash",
|
|
||||||
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 getFileFromPeer(@PathParam("hash") String hash58,
|
|
||||||
@PathParam("peer") String targetPeerAddress) {
|
|
||||||
try {
|
|
||||||
if (hash58 == null) {
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (targetPeer == null) {
|
|
||||||
LOGGER.info("Peer {} isn't connected", targetPeerAddress);
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean success = this.requestFile(hash58, 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 hashes",
|
|
||||||
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 hash58List[] = files.split(",");
|
|
||||||
for (String hash58 : hash58List) {
|
|
||||||
if (hash58 != null) {
|
|
||||||
boolean success = this.requestFile(hash58, targetPeer);
|
|
||||||
if (!success) {
|
|
||||||
LOGGER.info("Failed to request file {} from peer {}", hash58, targetPeerAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Response.ok("true").build();
|
|
||||||
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private boolean requestFile(String hash58, Peer targetPeer) {
|
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
|
||||||
|
|
||||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash58(hash58);
|
|
||||||
if (arbitraryDataFile.exists()) {
|
|
||||||
LOGGER.info("Data file {} already exists but we'll request it anyway", arbitraryDataFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] digest = null;
|
|
||||||
try {
|
|
||||||
digest = Base58.decode(hash58);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
LOGGER.info("Invalid base58 encoded string");
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA);
|
|
||||||
}
|
|
||||||
Message getArbitraryDataFileMessage = new GetArbitraryDataFileMessage(digest);
|
|
||||||
|
|
||||||
Message message = targetPeer.getResponse(getArbitraryDataFileMessage);
|
|
||||||
if (message == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (message.getType() == Message.MessageType.BLOCK_SUMMARIES) { // TODO: use dedicated message type here
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArbitraryDataFileMessage arbitraryDataFileMessage = (ArbitraryDataFileMessage) message;
|
|
||||||
arbitraryDataFile = arbitraryDataFileMessage.getArbitraryDataFile();
|
|
||||||
if (arbitraryDataFile == null || !arbitraryDataFile.exists()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LOGGER.info(String.format("Received file %s, size %d bytes", arbitraryDataFileMessage.getArbitraryDataFile(), arbitraryDataFileMessage.getArbitraryDataFile().size()));
|
|
||||||
return true;
|
|
||||||
} catch (ApiException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (DataException | InterruptedException e) {
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
|
||||||
@Path("/file/{hash}/build")
|
|
||||||
@Operation(
|
|
||||||
summary = "Join multiple chunks into a single file, 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 joined, 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 joinFiles(String files, @PathParam("hash") String combinedHash) {
|
|
||||||
|
|
||||||
if (combinedHash == null) {
|
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_CRITERIA);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash58(combinedHash);
|
|
||||||
if (arbitraryDataFile.exists()) {
|
|
||||||
LOGGER.info("We already have the combined file {}, but we'll join the chunks anyway.", combinedHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
String hash58List[] = files.split(",");
|
|
||||||
for (String hash58 : hash58List) {
|
|
||||||
if (hash58 != null) {
|
|
||||||
ArbitraryDataFileChunk chunk = ArbitraryDataFileChunk.fromHash58(hash58);
|
|
||||||
arbitraryDataFile.addChunk(chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean success = arbitraryDataFile.join();
|
|
||||||
if (success) {
|
|
||||||
if (combinedHash.equals(arbitraryDataFile.digest58())) {
|
|
||||||
LOGGER.info("Valid hash {} after joining {} files", arbitraryDataFile.digest58(), arbitraryDataFile.chunkCount());
|
|
||||||
return Response.ok("true").build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.ok("false").build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user