Skip to content
This repository was archived by the owner on Dec 6, 2024. It is now read-only.

Commit 946180d

Browse files
SynapticloopSynapticloop
authored andcommitted
Merge branch 'iterate-ch-feature/large-file-support'
2 parents 90c4646 + 1c3bd8a commit 946180d

27 files changed

Lines changed: 1202 additions & 157 deletions

src/main/java/synapticloop/b2/Action.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@
2727
* @author synapticloop
2828
*/
2929
public enum Action {
30+
/**
31+
* "hide" means a file version marking the file as hidden, so that it will not show up in b2_list_file_names.
32+
*/
3033
hide,
31-
upload
34+
/**
35+
* "upload" means a file that was uploaded.
36+
*/
37+
upload,
38+
/**
39+
* Pending multipart upload. "start" means that a large file has been started, but not finished or canceled.
40+
*/
41+
start
3242
}

src/main/java/synapticloop/b2/B2ApiClient.java

Lines changed: 103 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -16,45 +16,21 @@
1616
* this source code or binaries.
1717
*/
1818

19-
import java.io.File;
20-
import java.io.IOException;
21-
import java.io.InputStream;
22-
import java.util.List;
23-
import java.util.Map;
24-
2519
import org.apache.commons.io.FileUtils;
2620
import org.apache.http.HttpEntity;
2721
import org.apache.http.impl.client.CloseableHttpClient;
2822
import org.apache.http.impl.client.HttpClients;
29-
3023
import synapticloop.b2.exception.B2ApiException;
31-
import synapticloop.b2.request.B2AuthorizeAccountRequest;
32-
import synapticloop.b2.request.B2CreateBucketRequest;
33-
import synapticloop.b2.request.B2DeleteBucketRequest;
34-
import synapticloop.b2.request.B2DeleteFileVersionRequest;
35-
import synapticloop.b2.request.B2DownloadFileByIdRequest;
36-
import synapticloop.b2.request.B2DownloadFileByNameRequest;
37-
import synapticloop.b2.request.B2GetFileInfoRequest;
38-
import synapticloop.b2.request.B2GetUploadUrlRequest;
39-
import synapticloop.b2.request.B2HeadFileByIdRequest;
40-
import synapticloop.b2.request.B2HideFileRequest;
41-
import synapticloop.b2.request.B2ListBucketsRequest;
42-
import synapticloop.b2.request.B2ListFileNamesRequest;
43-
import synapticloop.b2.request.B2ListFileVersionsRequest;
44-
import synapticloop.b2.request.B2RequestProperties;
45-
import synapticloop.b2.request.B2UpdateBucketRequest;
46-
import synapticloop.b2.request.B2UploadFileRequest;
47-
import synapticloop.b2.response.B2AuthorizeAccountResponse;
48-
import synapticloop.b2.response.B2BucketResponse;
49-
import synapticloop.b2.response.B2DeleteFileVersionResponse;
50-
import synapticloop.b2.response.B2DownloadFileResponse;
51-
import synapticloop.b2.response.B2FileInfoResponse;
52-
import synapticloop.b2.response.B2FileResponse;
53-
import synapticloop.b2.response.B2GetUploadUrlResponse;
54-
import synapticloop.b2.response.B2HideFileResponse;
55-
import synapticloop.b2.response.B2ListFilesResponse;
24+
import synapticloop.b2.request.*;
25+
import synapticloop.b2.response.*;
5626
import synapticloop.b2.util.ChecksumHelper;
5727

28+
import java.io.File;
29+
import java.io.IOException;
30+
import java.io.InputStream;
31+
import java.util.List;
32+
import java.util.Map;
33+
5834
/**
5935
* This is a wrapper class for the underlying calls to the request/response
6036
* classes.
@@ -69,10 +45,10 @@ public class B2ApiClient {
6945

7046
/**
7147
* Create a B2ApiClient and authenticate
72-
*
48+
*
7349
* @param accountId The account id
7450
* @param applicationKey the application key
75-
*
51+
*
7652
* @throws B2ApiException if there was an error authenticating the account
7753
* @throws IOException if there was an error communicating with the API service
7854
*/
@@ -83,7 +59,7 @@ public B2ApiClient(String accountId, String applicationKey) throws B2ApiExceptio
8359

8460
/**
8561
* Must authenticate first before API actions are available. Using default HTTP client configuration
86-
*
62+
*
8763
* @see #authenticate(String, String)
8864
*/
8965
public B2ApiClient() {
@@ -92,9 +68,9 @@ public B2ApiClient() {
9268

9369
/**
9470
* Must authenticate first before API actions are available
95-
*
71+
*
9672
* @param client Shared HTTP client
97-
*
73+
*
9874
* @see #authenticate(String, String)
9975
*/
10076
public B2ApiClient(CloseableHttpClient client) {
@@ -109,7 +85,7 @@ public B2ApiClient(CloseableHttpClient client) {
10985
* @param applicationKey the application key
11086
*
11187
* @return the authorize account response
112-
*
88+
*
11389
* @throws B2ApiException if there was an error authenticating
11490
* @throws IOException if there was an error communicating with the API service
11591
*/
@@ -119,16 +95,16 @@ public B2AuthorizeAccountResponse authenticate(String accountId, String applicat
11995

12096
/**
12197
* Get the download URL for the authorized response
122-
*
98+
*
12399
* @return the download URL for the authorized response
124100
*/
125101
public String getDownloadUrl() {
126102
return b2AuthorizeAccountResponse.getDownloadUrl();
127103
}
128104

129105
/**
130-
* Get the API url
131-
*
106+
* Get the API url
107+
*
132108
* @return the API URL for backblaze
133109
*/
134110
public String getApiUrl() {
@@ -137,7 +113,7 @@ public String getApiUrl() {
137113

138114
/**
139115
* Release all resources from the connection pool.
140-
*
116+
*
141117
* @throws IOException if the client could not be closed
142118
*/
143119
public void close() throws IOException {
@@ -181,46 +157,6 @@ public B2BucketResponse deleteBucket(String bucketId) throws B2ApiException, IOE
181157
return new B2DeleteBucketRequest(client, b2AuthorizeAccountResponse, bucketId).getResponse();
182158
}
183159

184-
/**
185-
* Delete a bucket including all of the files that reside within the bucket.
186-
*
187-
* <strong>WARNING:</strong> this is a destructive action and will delete
188-
* everything within the bucket and the bucket itself
189-
*
190-
* @param bucketId the id of the bucket to delete
191-
*
192-
* @return the deleted bucket response
193-
*
194-
* @throws B2ApiException if there was an error deleting the bucket, or any
195-
* of the enclosed files
196-
* @throws IOException if there was an error communicating with the API service
197-
*/
198-
public B2BucketResponse deleteBucketFully(String bucketId) throws B2ApiException, IOException {
199-
B2ListFilesResponse b2ListFilesResponse = new B2ListFileVersionsRequest(client, b2AuthorizeAccountResponse, bucketId,
200-
B2RequestProperties.MAX_FILE_COUNT_RETURN).getResponse();
201-
String nextFileName = b2ListFilesResponse.getNextFileName();
202-
String nextFileId = b2ListFilesResponse.getNextFileId();
203-
while(true) {
204-
List<B2FileInfoResponse> files = b2ListFilesResponse.getFiles();
205-
for (B2FileInfoResponse b2FileInfoResponse : files) {
206-
new B2DeleteFileVersionRequest(client, b2AuthorizeAccountResponse,
207-
b2FileInfoResponse.getFileName(), b2FileInfoResponse.getFileId()).getResponse();
208-
}
209-
210-
if(null == nextFileName) {
211-
break;
212-
} else {
213-
b2ListFilesResponse = new B2ListFileVersionsRequest(client, b2AuthorizeAccountResponse, bucketId,
214-
B2RequestProperties.MAX_FILE_COUNT_RETURN, nextFileName, nextFileId).getResponse();
215-
nextFileName = b2ListFilesResponse.getNextFileName();
216-
nextFileId = b2ListFilesResponse.getNextFileId();
217-
}
218-
}
219-
220-
// now delete the bucket
221-
return new B2DeleteBucketRequest(client, b2AuthorizeAccountResponse, bucketId).getResponse();
222-
}
223-
224160
/**
225161
* Update a bucket to be a specified type
226162
*
@@ -264,7 +200,7 @@ public List<B2BucketResponse> listBuckets() throws B2ApiException, IOException {
264200
* @param fileId the file ID to retrieve the information on
265201
*
266202
* @return the File Response
267-
*
203+
*
268204
* @throws B2ApiException if something went wrong
269205
* @throws IOException if there was an error communicating with the API service
270206
*/
@@ -407,6 +343,90 @@ public B2FileResponse uploadFile(String bucketId, String fileName, File file) th
407343
file, ChecksumHelper.calculateSha1(file)).getResponse();
408344
}
409345

346+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
347+
*
348+
* LARGE FILE UPLOAD API ACTIONS
349+
*
350+
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
351+
352+
/**
353+
* Start large file upload
354+
*
355+
* @param bucketId the id of the bucket
356+
* @param fileName the name of the file that will be placed in the bucket
357+
* @param mimeType the mime type of the file, if null, then the mime type
358+
* will be attempted to be automatically mapped by the backblaze B2 API
359+
* see <a href="https://www.backblaze.com/b2/docs/content-types.html">https://www.backblaze.com/b2/docs/content-types.html</a>
360+
* for a list of content type mappings.
361+
* @param fileInfo the file info map which will be set as 'X-Bz-Info-' headers
362+
* @return The unique identifier for the file
363+
* @throws B2ApiException if there was an error uploading the file
364+
*/
365+
public B2StartLargeFileResponse startLargeFileUpload(String bucketId, String fileName, String mimeType, Map<String, String> fileInfo) throws B2ApiException, IOException {
366+
return new B2StartLargeFileRequest(client, b2AuthorizeAccountResponse, bucketId, fileName, mimeType, fileInfo).getResponse();
367+
}
368+
369+
/**
370+
* Cancel large file upload
371+
*
372+
* @param fileId The ID returned by b2_start_large_file.
373+
* @return File response
374+
* @throws B2ApiException if there was an error canceling the upload
375+
*/
376+
public B2FileResponse cancelLargeFileUpload(String fileId) throws B2ApiException, IOException {
377+
return new B2CancelLargeFileRequest(client, b2AuthorizeAccountResponse, fileId).getResponse();
378+
}
379+
380+
/**
381+
* Finish large file upload. Converts the parts that have been uploaded into a single B2 file.
382+
*
383+
* @param fileId The ID returned by b2_start_large_file.
384+
* @return File response
385+
* @throws B2ApiException if there was an error finishing the upload
386+
*/
387+
public B2FinishLargeFileResponse finishLargeFileUpload(String fileId, String[] partSha1Array) throws B2ApiException, IOException {
388+
return new B2FinishLargeFileRequest(client, b2AuthorizeAccountResponse, fileId, partSha1Array).getResponse();
389+
}
390+
391+
/**
392+
* Upload large file upload part
393+
*
394+
* @param fileId the id of the file to upload
395+
* @param partNumber A number from 1 to 10000. The parts uploaded for one file must have contiguous numbers, starting with 1.
396+
* @param entity Part content body
397+
* @param sha1Checksum the checksum for the part
398+
* @return Upload response
399+
* @throws B2ApiException if there was an error uploading the file
400+
*/
401+
public B2UploadPartResponse uploadLargeFilePart(String fileId, int partNumber, HttpEntity entity, String sha1Checksum) throws B2ApiException, IOException {
402+
final B2GetUploadPartUrlResponse b2GetUploadUrlResponse = new B2GetUploadPartUrlRequest(client, b2AuthorizeAccountResponse, fileId).getResponse();
403+
return new B2UploadPartRequest(client, b2AuthorizeAccountResponse, b2GetUploadUrlResponse, partNumber, entity, sha1Checksum).getResponse();
404+
}
405+
406+
/**
407+
* Lists information about large file uploads that have been started, but have not been finished or canceled.
408+
* Uploads are listed in the order they were started, with the oldest one first
409+
*
410+
* @param bucketId the id of the bucket
411+
* @return An array of objects, each one describing one unfinished file
412+
* @throws B2ApiException if there was an error listing the files
413+
* @throws IOException if there was an error communicating with the API service
414+
*/
415+
public B2ListFilesResponse listUnfinishedLargeFiles(String bucketId, String startFileId, Integer maxFileCount) throws B2ApiException, IOException {
416+
return new B2ListUnfinishedLargeFilesRequest(client, b2AuthorizeAccountResponse, bucketId, startFileId, maxFileCount).getResponse();
417+
}
418+
419+
/**
420+
* @param fileId The ID returned by b2_start_large_file. This is the file whose parts will be listed.
421+
* @param startPartNumber Null to start
422+
* @param maxPartCount The maximum number of parts to return
423+
* @return This call returns at most 1000 entries, but it can be called repeatedly to scan through all of the parts for an upload.
424+
* @throws B2ApiException if there was an error listing the parts
425+
* @throws IOException if there was an error communicating with the API service
426+
*/
427+
public B2ListPartsResponse listParts(String fileId, Integer startPartNumber, Integer maxPartCount) throws B2ApiException, IOException {
428+
return new B2ListPartsRequest(client, b2AuthorizeAccountResponse, fileId, startPartNumber, maxPartCount).getResponse();
429+
}
410430

411431
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
412432
*

0 commit comments

Comments
 (0)