|
9 | 9 | import com.volcengine.error.SdkError;
|
10 | 10 | import com.volcengine.helper.Utils;
|
11 | 11 | import com.volcengine.model.ServiceInfo;
|
| 12 | +import com.volcengine.model.beans.PartInputStream; |
| 13 | +import com.volcengine.model.imagex.v2.ApplyVpcUploadInfoQuery; |
| 14 | +import com.volcengine.model.imagex.v2.ApplyVpcUploadInfoRes; |
| 15 | +import com.volcengine.model.imagex.v2.ApplyVpcUploadInfoResResult; |
| 16 | +import com.volcengine.model.imagex.v2.ApplyVpcUploadInfoResResultPartUploadInfo; |
12 | 17 | import com.volcengine.model.request.ApplyImageUploadRequest;
|
13 | 18 | import com.volcengine.model.request.CommitImageUploadRequest;
|
14 | 19 | import com.volcengine.model.request.CommitImageUploadRequestBody;
|
| 20 | +import com.volcengine.model.request.VpcUploadRequest; |
15 | 21 | import com.volcengine.model.response.ApplyImageUploadResponse;
|
16 | 22 | import com.volcengine.model.response.CommitImageUploadResponse;
|
17 | 23 | import com.volcengine.model.response.RawResponse;
|
|
21 | 27 | import com.volcengine.model.sts2.Statement;
|
22 | 28 | import com.volcengine.util.Sts2Utils;
|
23 | 29 | import com.volcengine.util.Time;
|
| 30 | +import org.apache.http.Header; |
24 | 31 | import org.apache.http.HttpResponse;
|
25 | 32 | import org.apache.http.NameValuePair;
|
26 | 33 | import org.apache.http.util.EntityUtils;
|
27 | 34 |
|
28 |
| -import java.io.BufferedInputStream; |
29 |
| -import java.io.ByteArrayOutputStream; |
30 |
| -import java.io.InputStream; |
| 35 | +import java.io.*; |
31 | 36 | import java.net.URI;
|
32 | 37 | import java.util.*;
|
33 | 38 | import java.util.logging.Level;
|
@@ -344,6 +349,218 @@ public CommitImageUploadResponse uploadImages(ApplyImageUploadRequest request, L
|
344 | 349 | return commitImageUpload(commitRequest);
|
345 | 350 | }
|
346 | 351 |
|
| 352 | + public CommitImageUploadResponse vpcUploadImage(VpcUploadRequest request) throws Exception { |
| 353 | + if ((request.getFilePath() == null || request.getFilePath().isEmpty()) && (request.getData() == null || request.getData().length == 0)) { |
| 354 | + throw new Exception("filePath and data can not be empty or not empty at the same time"); |
| 355 | + } |
| 356 | + |
| 357 | + if ((request.getFilePath() != null && !request.getFilePath().isEmpty()) && (request.getData() != null && request.getData().length != 0)) { |
| 358 | + throw new Exception("filePath and data can not be not empty at the same time"); |
| 359 | + } |
| 360 | + |
| 361 | + Long fileSize = 0L; |
| 362 | + File file = null; |
| 363 | + boolean isFile = false; |
| 364 | + if (request.getFilePath() == null || request.getFilePath().isEmpty()) { |
| 365 | + fileSize = (long) request.getData().length; |
| 366 | + } else { |
| 367 | + file = new File(request.getFilePath()); |
| 368 | + if (!(file.isFile() && file.exists())) { |
| 369 | + throw new Exception(SdkError.getErrorDesc(SdkError.ENOFILE)); |
| 370 | + } |
| 371 | + fileSize = file.length(); |
| 372 | + isFile = true; |
| 373 | + } |
| 374 | + |
| 375 | + ApplyVpcUploadInfoQuery applyVpcUploadInfoQuery = new ApplyVpcUploadInfoQuery(); |
| 376 | + applyVpcUploadInfoQuery.setServiceId(request.getServiceId()); |
| 377 | + applyVpcUploadInfoQuery.setStoreKey(request.getStoreKey()); |
| 378 | + applyVpcUploadInfoQuery.setPrefix(request.getPrefix()); |
| 379 | + applyVpcUploadInfoQuery.setFileExtension(request.getFileExtension()); |
| 380 | + applyVpcUploadInfoQuery.setContentType(request.getContentType()); |
| 381 | + applyVpcUploadInfoQuery.setOverwrite(request.getOverwrite()); |
| 382 | + applyVpcUploadInfoQuery.setStorageClass(request.getStorageClass()); |
| 383 | + applyVpcUploadInfoQuery.setPartSize(request.getPartSize()); |
| 384 | + applyVpcUploadInfoQuery.setFileSize(fileSize); |
| 385 | + |
| 386 | + // apply upload |
| 387 | + ApplyVpcUploadInfoRes applyVpcUploadInfoRes = applyVpcUploadInfo(applyVpcUploadInfoQuery); |
| 388 | + ApplyVpcUploadInfoResResult uploadAddr = applyVpcUploadInfoRes.getResult(); |
| 389 | + if (applyVpcUploadInfoRes.getResponseMetadata() == null) { |
| 390 | + throw new Exception("apply upload response metadata is null"); |
| 391 | + } |
| 392 | + if (uploadAddr == null || uploadAddr.getUploadMode().isEmpty()) { |
| 393 | + throw new Exception("apply upload result is null. request id:" + applyVpcUploadInfoRes.getResponseMetadata().getRequestId()); |
| 394 | + } |
| 395 | + |
| 396 | + String sessionKey = uploadAddr.getSessionKey(); |
| 397 | + |
| 398 | + List<String> successOids = new ArrayList<String>(); |
| 399 | + CommitImageUploadRequest commitRequest = new CommitImageUploadRequest(); |
| 400 | + commitRequest.setServiceId(request.getServiceId()); |
| 401 | + commitRequest.setSkipMeta(request.getSkipMeta()); |
| 402 | + commitRequest.setSessionKey(sessionKey); |
| 403 | + commitRequest.setSuccessOids(successOids); |
| 404 | + if (request.getCommitParam() != null) { |
| 405 | + commitRequest.setFunctions(request.getCommitParam().getFunctions()); |
| 406 | + commitRequest.setOptionInfos(request.getCommitParam().getOptionInfos()); |
| 407 | + } |
| 408 | + |
| 409 | + try { |
| 410 | + vpcUpload(uploadAddr, file, request.getData(), isFile); |
| 411 | + }catch (Exception e){ |
| 412 | + commitImageUpload(commitRequest); |
| 413 | + throw e; |
| 414 | + } |
| 415 | + |
| 416 | + successOids.add(uploadAddr.getOid()); |
| 417 | + // commit upload |
| 418 | + commitRequest.setSuccessOids(successOids); |
| 419 | + return commitImageUpload(commitRequest); |
| 420 | + } |
| 421 | + |
| 422 | + private void vpcUpload(ApplyVpcUploadInfoResResult uploadAddr, File file, byte[] data, boolean isFile) throws Exception { |
| 423 | + if (uploadAddr.getUploadMode().equals("direct")) { |
| 424 | + vpcPut(uploadAddr, file, data, isFile); |
| 425 | + } else if (uploadAddr.getUploadMode().equals("part")) { |
| 426 | + vpcPartUpload(uploadAddr.getPartUploadInfo(), file, data, isFile); |
| 427 | + } else{ |
| 428 | + throw new Exception("unexpected mode "+ uploadAddr.getUploadMode()); |
| 429 | + } |
| 430 | + } |
| 431 | + |
| 432 | + private void vpcPartUpload(ApplyVpcUploadInfoResResultPartUploadInfo partUploadInfo, File file, byte[] data, boolean isFile) throws Exception { |
| 433 | + if (partUploadInfo == null || partUploadInfo.getPartSize() == 0) { |
| 434 | + throw new Exception("part upload info is null"); |
| 435 | + } |
| 436 | + long size = 0; |
| 437 | + if (isFile) { |
| 438 | + size = file.length(); |
| 439 | + } else { |
| 440 | + size = data.length; |
| 441 | + } |
| 442 | + long chunkSize = partUploadInfo.getPartSize(); |
| 443 | + int totalNum = (int) (size / chunkSize); |
| 444 | + long lastPartSize = size % chunkSize; |
| 445 | + |
| 446 | + if ((lastPartSize == 0 && partUploadInfo.getPartPutURLs().size() != totalNum) || |
| 447 | + (lastPartSize != 0 && partUploadInfo.getPartPutURLs().size()!= totalNum + 1)) { |
| 448 | + throw new Exception("part upload info is invalid"); |
| 449 | + } |
| 450 | + |
| 451 | + List<String> etagList = new ArrayList<>(); |
| 452 | + long offset = 0; |
| 453 | + for (int i = 0; i < partUploadInfo.getPartPutURLs().size(); i++) { |
| 454 | + String putUrl = partUploadInfo.getPartPutURLs().get(i); |
| 455 | + long uploadPartSize = chunkSize; |
| 456 | + if (i == partUploadInfo.getPartPutURLs().size() - 1 && lastPartSize != 0) { |
| 457 | + uploadPartSize = lastPartSize; |
| 458 | + } |
| 459 | + String etag = vpcPartPut(putUrl, file, data, isFile, offset, uploadPartSize); |
| 460 | + etagList.add(etag); |
| 461 | + offset += uploadPartSize; |
| 462 | + } |
| 463 | + |
| 464 | + vpcPost(partUploadInfo, etagList); |
| 465 | + } |
| 466 | + |
| 467 | + private void vpcPost(ApplyVpcUploadInfoResResultPartUploadInfo partUploadInfo, List<String> etagList) throws Exception { |
| 468 | + String partsInfo = IntStream.range(0, etagList.size()).mapToObj(i -> String.format("{\"PartNumber\":%d,\"Etag\":%s}", i + 1, etagList.get(i))).collect(Collectors.joining(",", "", "")); |
| 469 | + String body = String.format("{\"Parts\": [%s]}", partsInfo); |
| 470 | + |
| 471 | + String postUrl = partUploadInfo.getCompletePartURL(); |
| 472 | + Map<String, String> headers = new HashMap<>(); |
| 473 | + if (partUploadInfo.getCompletePartURLHeaders() != null){ |
| 474 | + partUploadInfo.getCompletePartURLHeaders().forEach(item -> headers.put(item.getKey(), item.getValue())); |
| 475 | + } |
| 476 | + HttpResponse httpResponse = postDataWithResponse(postUrl, body.getBytes(), headers); |
| 477 | + |
| 478 | + if (httpResponse == null){ |
| 479 | + throw new Exception("http null resp"); |
| 480 | + } |
| 481 | + |
| 482 | + if (httpResponse.getStatusLine().getStatusCode() != 200){ |
| 483 | + Header logIdHeader = httpResponse.getFirstHeader("x-tos-request-id"); |
| 484 | + String logId = ""; |
| 485 | + if (logIdHeader != null){ |
| 486 | + logId = logIdHeader.getValue(); |
| 487 | + } |
| 488 | + throw new Exception("post error: code "+ httpResponse.getStatusLine().getStatusCode() + " logId " + logId); |
| 489 | + } |
| 490 | + } |
| 491 | + |
| 492 | + private String vpcPartPut(String putUrl, File file, byte[] data, boolean isFile, long offset, long chunkSize) throws Exception { |
| 493 | + HttpResponse httpResponse = null; |
| 494 | + if (isFile){ |
| 495 | + try (InputStream fileInputStream = new FileInputStream(file)) { |
| 496 | + fileInputStream.skip(offset); |
| 497 | + try (InputStream inputStream = com.volcengine.helper.Utils.newRepeatableInputStream(new PartInputStream(fileInputStream, chunkSize))) { |
| 498 | + httpResponse = putDataWithResponse(putUrl, inputStream, null); |
| 499 | + } catch (Exception e) { |
| 500 | + throw e; |
| 501 | + } |
| 502 | + } |
| 503 | + } else { |
| 504 | + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data); |
| 505 | + byteArrayInputStream.skip(offset); |
| 506 | + try (InputStream inputStream = com.volcengine.helper.Utils.newRepeatableInputStream(new PartInputStream(byteArrayInputStream, chunkSize))) { |
| 507 | + httpResponse = putDataWithResponse(putUrl, inputStream, null); |
| 508 | + }catch (Exception e) { |
| 509 | + throw e; |
| 510 | + } |
| 511 | + } |
| 512 | + |
| 513 | + if (httpResponse == null){ |
| 514 | + throw new Exception("http null resp"); |
| 515 | + } |
| 516 | + |
| 517 | + if (httpResponse.getStatusLine().getStatusCode() != 200){ |
| 518 | + Header logIdHeader = httpResponse.getFirstHeader("x-tos-request-id"); |
| 519 | + String logId = ""; |
| 520 | + if (logIdHeader != null){ |
| 521 | + logId = logIdHeader.getValue(); |
| 522 | + } |
| 523 | + throw new Exception("put error: code "+ httpResponse.getStatusLine().getStatusCode() + " logId " + logId); |
| 524 | + } |
| 525 | + String etag = ""; |
| 526 | + Header etagHeader = httpResponse.getFirstHeader("ETag"); |
| 527 | + if (etagHeader != null){ |
| 528 | + etag = etagHeader.getValue(); |
| 529 | + } |
| 530 | + |
| 531 | + return etag; |
| 532 | + } |
| 533 | + |
| 534 | + private void vpcPut(ApplyVpcUploadInfoResResult uploadAddr, File file, byte[] data, boolean isFile) throws Exception { |
| 535 | + String putUrl = uploadAddr.getPutURL(); |
| 536 | + Map<String, String> headers = new HashMap<>(); |
| 537 | + if (uploadAddr.getPutURLHeaders() != null){ |
| 538 | + uploadAddr.getPutURLHeaders().forEach(item -> headers.put(item.getKey(), item.getValue())); |
| 539 | + } |
| 540 | + HttpResponse httpResponse = null; |
| 541 | + if (isFile) { |
| 542 | + try (InputStream inputStream = com.volcengine.helper.Utils.newRepeatableInputStream(new java.io.FileInputStream(file))) { |
| 543 | + inputStream.mark(0); |
| 544 | + httpResponse = putDataWithResponse(putUrl, inputStream, headers); |
| 545 | + } |
| 546 | + } else { |
| 547 | + httpResponse = putDataWithResponse(putUrl, data, headers); |
| 548 | + } |
| 549 | + |
| 550 | + if (httpResponse == null){ |
| 551 | + throw new Exception("http null resp"); |
| 552 | + } |
| 553 | + |
| 554 | + if (httpResponse.getStatusLine().getStatusCode() != 200){ |
| 555 | + Header logIdHeader = httpResponse.getFirstHeader("x-tos-request-id"); |
| 556 | + String logId = ""; |
| 557 | + if (logIdHeader != null){ |
| 558 | + logId = logIdHeader.getValue(); |
| 559 | + } |
| 560 | + throw new Exception("put error: code "+ httpResponse.getStatusLine().getStatusCode() + " logId " + logId); |
| 561 | + } |
| 562 | + } |
| 563 | + |
347 | 564 | private void applyRespGuard(ApplyImageUploadResponse applyResp, int expectSize) {
|
348 | 565 | if (applyResp.getResult() == null) {
|
349 | 566 | throw new IllegalStateException("apply upload result is null");
|
|
0 commit comments