diff --git a/pom.xml b/pom.xml index 19133602..147eafe6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ ru.kontur.diadoc diadocsdk - 3.23.0-dev.5429.28650 + 3.20.0-dev.5429.28865 jar diff --git a/proto/FileToUpload.proto b/proto/FileToUpload.proto deleted file mode 100644 index b87ce37f..00000000 --- a/proto/FileToUpload.proto +++ /dev/null @@ -1,6 +0,0 @@ -package Diadoc.Api.Proto; - -message FileToUpload { - required bytes Content = 1; - optional string FileExtension = 2; -} \ No newline at end of file diff --git a/src/main/java/Diadoc/Api/shelf/ShelfClient.java b/src/main/java/Diadoc/Api/shelf/ShelfClient.java index bc383d52..688ebb9a 100644 --- a/src/main/java/Diadoc/Api/shelf/ShelfClient.java +++ b/src/main/java/Diadoc/Api/shelf/ShelfClient.java @@ -9,6 +9,7 @@ import org.apache.http.client.methods.RequestBuilder; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ByteArrayEntity; +import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.net.URISyntaxException; @@ -36,6 +37,11 @@ public int getShelfUploadMaxAttemptsCount() { return SHELF_MAX_ATTEMPTS; } + /** + * Use shelfDownload instead + */ + + @Deprecated public byte[] shelfDownload(String nameOnShelf) throws DiadocSdkException { if (!nameOnShelf.contains(SHELF_PATH_PREFIX)) nameOnShelf = SHELF_PATH_PREFIX + "/" + nameOnShelf; @@ -51,6 +57,24 @@ public byte[] shelfDownload(String nameOnShelf) throws DiadocSdkException { } } + public byte[] shelfDownloadV2(String fileName) throws DiadocSdkException { + try { + var request = RequestBuilder.get( + new URIBuilder(diadocHttpClient.getBaseUrl()) + .setPath("/V2/ShelfDownload") + .addParameter("fileName", fileName) + .build()); + return diadocHttpClient.performRequest(request); + } catch (URISyntaxException | IOException e) { + throw new DiadocSdkException(e); + } + } + + /** + * Use uploadFileToShelfV2 or uploadLargeFileToShelf instead + */ + + @Deprecated public String uploadFileToShelf(byte[] data) throws DiadocSdkException { if (data == null) throw new IllegalArgumentException("data"); @@ -64,7 +88,7 @@ public String uploadFileToShelf(byte[] data) throws DiadocSdkException { var httpErrors = new ArrayList(); int attempts = 0; - while (missingParts.size() > 0) { + while (!missingParts.isEmpty()) { if (++attempts > SHELF_MAX_ATTEMPTS) throw new DiadocSdkException("Reached the limit of attempts to send a file. " + formatHttpErrors(httpErrors)); @@ -84,38 +108,187 @@ public String uploadFileToShelf(byte[] data) throws DiadocSdkException { return nameOnShelf; } -// public String uploadFileToShelfV2(FileToUpload file) throws DiadocSdkException { -// if (file == null) -// throw new IllegalArgumentException("file"); -// -// var url = new URIBuilder(diadocHttpClient.getBaseUrl()).setPath("/V2/ShelfUpload"); -// -// try { -// var response = diadocHttpClient.getResponse(RequestBuilder.post(url.build()).setEntity(new ByteArrayEntity(file.toByteArray()))); -// if (response.getStatusCode() != HttpStatus.SC_OK) { -// if (SHELF_NON_RETRIABLE_STATUS_CODES.contains(response.getStatusCode())) { -// throw new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode()); -// } -// -// httpErrors.add(new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode())); -// return null; -// } -// -// responseContent = response.getContent(); -// -// } catch (IOException e) { -// httpErrors.add(e); -// return null; -// } -// -// if (responseContent == null || responseContent.length == 0) -// return null; -// -// String responseString = new String(responseContent, StandardCharsets.UTF_8); -// -// int[] missingParts = new Gson().fromJson(responseString, int[].class); -// return Arrays.stream(missingParts).boxed().collect(Collectors.toList()); -// } + public String uploadFileToShelfV2(byte[] content, @Nullable String fileExtension) throws DiadocSdkException, URISyntaxException, DiadocException { + if (content == null) + throw new IllegalArgumentException("content"); + + var httpErrors = new ArrayList(); + var url = new URIBuilder(diadocHttpClient.getBaseUrl()) + .setPath("/V2/ShelfUpload") + .addParameter("fileExtension", fileExtension); + + byte[] responseContent; + for (var i = 0; i < SHELF_MAX_ATTEMPTS; i++) + { + try { + var response = diadocHttpClient.getResponse(RequestBuilder.post(url.build()).setEntity(new ByteArrayEntity(content))); + if (response.getStatusCode() != HttpStatus.SC_OK) { + if (SHELF_NON_RETRIABLE_STATUS_CODES.contains(response.getStatusCode())) { + throw new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode()); + } + + httpErrors.add(new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode())); + } + + responseContent = response.getContent(); + if (responseContent == null || responseContent.length == 0) { + continue; + } + + return new String(responseContent, StandardCharsets.UTF_8); + } + catch (IOException e) { + httpErrors.add(e); + } + } + + throw new DiadocSdkException("Reached the limit of attempts to send a file. " + formatHttpErrors(httpErrors)); + } + + public String uploadLargeFileToShelf(byte[] content, @Nullable String fileExtension) throws DiadocSdkException, URISyntaxException, DiadocException { + if (content == null) + throw new IllegalArgumentException("content"); + + var parts = splitDataIntoParts(content); + List missingParts = new ArrayList<>(); + + for (int i = 0; i < parts.size(); i++) + missingParts.add(i); + + var httpErrors = new ArrayList(); + int attempts = 0; + String fileName = null; + + while (!missingParts.isEmpty()) { + if (++attempts > SHELF_MAX_ATTEMPTS){ + throw new DiadocSdkException("Reached the limit of attempts to send a file. " + formatHttpErrors(httpErrors)); + } + + int partsCount = parts.size(); + int lastPartIndex = partsCount - 1; + //always add last part for stability + if (!missingParts.contains(lastPartIndex)) + missingParts.add(lastPartIndex); + + try { + if (fileName == null) { + fileName = shelfUploadPartInit(parts.get(0), missingParts, httpErrors, fileExtension); + } + + if (fileName != null) { + missingParts = shelfUploadParts(fileName, parts, missingParts, httpErrors); + } + } catch (URISyntaxException | DiadocException e) { + e.printStackTrace(); + throw new DiadocSdkException(e); + } + } + return fileName; + } + + private String shelfUploadPartInit( + ByteArraySegment firstPart, + List missingParts, + List httpErrors, + @Nullable String fileExtension) throws URISyntaxException, DiadocException { + var url = new URIBuilder(diadocHttpClient.getBaseUrl()) + .setPath("/ShelfUploadPartInit") + .addParameter("fileExtension", fileExtension); + if (missingParts.size() == 1) + { + url.addParameter("isLastPart", "true"); + } + + try + { + var response = diadocHttpClient.getResponse(RequestBuilder.post(url.build()).setEntity(new ByteArrayEntity(firstPart.getBytes()))); + if (response.getStatusCode() != HttpStatus.SC_OK) { + if (SHELF_NON_RETRIABLE_STATUS_CODES.contains(response.getStatusCode())) { + throw new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode()); + } + + httpErrors.add(new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode())); + } + + var responseContent = response.getContent(); + if (responseContent == null || responseContent.length == 0) + return null; + + missingParts.remove(0); + return new String(responseContent, StandardCharsets.UTF_8); + + } catch (IOException e) { + httpErrors.add(e); + } + + return null; + } + + private List shelfUploadParts( + String fileName, + List parts, + List missingParts, + List httpErrors) throws URISyntaxException, DiadocException { + Set lastMissingParts = new HashSet<>(missingParts); + int maxProcessedPartIndex = -1; + + for (int partIndex : missingParts) { + boolean isLastPart = partIndex == parts.size() - 1; + List newMissingParts = uploadPart(fileName, parts.get(partIndex), partIndex, isLastPart, httpErrors); + if (newMissingParts != null) { + if (partIndex > maxProcessedPartIndex) { + lastMissingParts.clear(); + lastMissingParts.addAll(newMissingParts); + + maxProcessedPartIndex = partIndex; + } + } else { + lastMissingParts.add(partIndex); + } + } + return new ArrayList<>(lastMissingParts); + } + + private List uploadPart( + String fileName, + ByteArraySegment part, + Integer partIndex, + Boolean isLast, + List httpErrors) throws URISyntaxException, DiadocException { + var url = new URIBuilder(diadocHttpClient.getBaseUrl()) + .setPath("/ShelfUploadPart") + .addParameter("fileName", fileName) + .addParameter("partIndex", Integer.toString(partIndex)) + .addParameter("isLastPart", Boolean.toString(isLast)); + + byte[] responseContent; + + try { + var response = diadocHttpClient.getResponse(RequestBuilder.post(url.build()).setEntity(new ByteArrayEntity(part.getBytes()))); + if (response.getStatusCode() != HttpStatus.SC_OK) { + if (SHELF_NON_RETRIABLE_STATUS_CODES.contains(response.getStatusCode())) { + throw new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode()); + } + + httpErrors.add(new DiadocException(formatResponseMessage(response.getReason(), response.getStatusCode()), response.getStatusCode())); + return null; + } + + responseContent = response.getContent(); + + } catch (IOException e) { + httpErrors.add(e); + return null; + } + + if (responseContent == null || responseContent.length == 0) + return null; + + String responseString = new String(responseContent, StandardCharsets.UTF_8); + + int[] missingParts = new Gson().fromJson(responseString, int[].class); + return Arrays.stream(missingParts).boxed().collect(Collectors.toList()); + } private String createNameOnShelf() { return String.format("java_api-%s", UUID.randomUUID().toString().replaceAll("-", ""));