-
-
Notifications
You must be signed in to change notification settings - Fork 735
Download ParseFile content to file instead of memory #53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
32876a9
d4d754f
228790f
8c3ed88
dd591a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,13 @@ public File getCacheFile(ParseFile.State state) { | |
return new File(cachePath, state.name()); | ||
} | ||
|
||
/* package for tests */ File getTempFile(ParseFile.State state) { | ||
if (state.url() == null) { | ||
return null; | ||
} | ||
return new File(cachePath, state.url() + ".tmp"); | ||
} | ||
|
||
public boolean isDataAvailable(ParseFile.State state) { | ||
return getCacheFile(state).exists(); | ||
} | ||
|
@@ -172,46 +179,55 @@ public Task<File> fetchAsync( | |
if (cancellationToken != null && cancellationToken.isCancelled()) { | ||
return Task.cancelled(); | ||
} | ||
final File file = getCacheFile(state); | ||
final File cacheFile = getCacheFile(state); | ||
return Task.call(new Callable<Boolean>() { | ||
@Override | ||
public Boolean call() throws Exception { | ||
return file.exists(); | ||
return cacheFile.exists(); | ||
} | ||
}, Task.BACKGROUND_EXECUTOR).continueWithTask(new Continuation<Boolean, Task<File>>() { | ||
}, ParseExecutors.io()).continueWithTask(new Continuation<Boolean, Task<File>>() { | ||
@Override | ||
public Task<File> then(Task<Boolean> task) throws Exception { | ||
boolean result = task.getResult(); | ||
if (result) { | ||
return Task.forResult(file); | ||
return Task.forResult(cacheFile); | ||
} | ||
if (cancellationToken != null && cancellationToken.isCancelled()) { | ||
return Task.cancelled(); | ||
} | ||
|
||
// Generate the temp file path for caching ParseFile content based on ParseFile's url | ||
// The reason we do not write to the cacheFile directly is because there is no way we can | ||
// verify if a cacheFile is complete or not. If download is interrupted in the middle, next | ||
// time when we download the ParseFile, since cacheFile has already existed, we will return | ||
// this incomplete cacheFile | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes sense since although we use a Would it make sense to instead keep a mapping of URL -> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is useful but we have already had cacheFile. Before we fetch, we check whether the cacheFile exist or not. So instead of checking file exists or not in disk, you want to keep a in-memory map to make the checking faster? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Never mind, I thought this comment was with regards to asynchronously downloading a |
||
final File tempFile = getTempFile(state); | ||
|
||
// network | ||
final ParseAWSRequest request = new ParseAWSRequest(ParseHttpRequest.Method.GET, state.url()); | ||
final ParseAWSRequest request = | ||
new ParseAWSRequest(ParseHttpRequest.Method.GET, state.url(), tempFile); | ||
|
||
// TODO(grantland): Stream response directly to file t5042019 | ||
// We do not need to delete the temp file since we always try to overwrite it | ||
return request.executeAsync( | ||
awsClient(), | ||
null, | ||
downloadProgressCallback, | ||
cancellationToken).onSuccess(new Continuation<byte[], File>() { | ||
cancellationToken).continueWithTask(new Continuation<Void, Task<File>>() { | ||
@Override | ||
public File then(Task<byte[]> task) throws Exception { | ||
public Task<File> then(Task<Void> task) throws Exception { | ||
// If the top-level task was cancelled, don't actually set the data -- just move on. | ||
if (cancellationToken != null && cancellationToken.isCancelled()) { | ||
throw new CancellationException(); | ||
} | ||
|
||
byte[] data = task.getResult(); | ||
if (data != null) { | ||
ParseFileUtils.writeByteArrayToFile(file, data); | ||
if (task.isFaulted()) { | ||
ParseFileUtils.deleteQuietly(tempFile); | ||
return task.cast(); | ||
} | ||
return file; | ||
|
||
ParseFileUtils.moveFile(tempFile, cacheFile); | ||
return Task.forResult(cacheFile); | ||
} | ||
}); | ||
}, ParseExecutors.io()); | ||
} | ||
}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be easier if we made the generic
File
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, what
ParseAWSRequest
do is to read response stream and write data to a tempFile. Since we have already injected the tempFile (which means the caller already holds the file pointer), I changebyte[]
toVoid
. But if you think return the tempFile is cleaner, I can change this.