-
Notifications
You must be signed in to change notification settings - Fork 9.2k
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
Upload progress recipe #1528
Upload progress recipe #1528
Changes from all commits
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 |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* Copyright (C) 2015 Square, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.squareup.okhttp.recipes; | ||
|
||
import com.squareup.okhttp.MediaType; | ||
import com.squareup.okhttp.OkHttpClient; | ||
import com.squareup.okhttp.Request; | ||
import com.squareup.okhttp.RequestBody; | ||
import com.squareup.okhttp.Response; | ||
import okio.Buffer; | ||
import okio.BufferedSink; | ||
import okio.ForwardingSink; | ||
import okio.Okio; | ||
import okio.Sink; | ||
import okio.Source; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
|
||
public final class UploadProgress { | ||
/** | ||
* The imgur client ID for OkHttp recipes. If you're using imgur for anything | ||
* other than running these examples, please request your own client ID! | ||
* https://api.imgur.com/oauth2 | ||
*/ | ||
private static final String IMGUR_CLIENT_ID = "9199fdef135c122"; | ||
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png"); | ||
|
||
private final OkHttpClient client = new OkHttpClient(); | ||
|
||
public void run() throws Exception { | ||
final ProgressListener progressListener = new ProgressListener() { | ||
@Override public void update(long bytesWritten, long contentLength, boolean done) { | ||
System.out.println(bytesWritten); | ||
System.out.println(contentLength); | ||
System.out.println(done); | ||
System.out.format("%d%% done\n", (100 * bytesWritten) / contentLength); | ||
} | ||
}; | ||
|
||
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image | ||
Request request = new Request.Builder() | ||
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID) | ||
.url("https://api.imgur.com/3/image") | ||
.post(new ProgressRequestBody( | ||
MEDIA_TYPE_PNG, | ||
new File("website/static/logo-square.png"), | ||
progressListener)) | ||
.build(); | ||
|
||
Response response = client.newCall(request).execute(); | ||
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); | ||
|
||
System.out.println(response.body().string()); | ||
} | ||
|
||
public static void main(String... args) throws Exception { | ||
new UploadProgress().run(); | ||
} | ||
|
||
private static class ProgressRequestBody extends RequestBody { | ||
|
||
private final ProgressListener progressListener; | ||
private final MediaType contentType; | ||
private final File file; | ||
|
||
public ProgressRequestBody(MediaType contentType, File file, | ||
ProgressListener progressListener) { | ||
this.contentType = contentType; | ||
this.file = file; | ||
this.progressListener = progressListener; | ||
} | ||
|
||
@Override public MediaType contentType() { | ||
return contentType; | ||
} | ||
|
||
@Override public long contentLength() { | ||
return file.length(); | ||
} | ||
|
||
@Override public void writeTo(BufferedSink sink) throws IOException { | ||
BufferedSink bufferedSink = Okio.buffer(sink(sink)); | ||
Source source = Okio.source(file); | ||
bufferedSink.writeAll(source); | ||
source.close(); | ||
bufferedSink.close(); | ||
} | ||
|
||
public Sink sink(Sink sink) { | ||
return new ForwardingSink(sink) { | ||
long totalBytesWritten = 0L; | ||
|
||
@Override public void write(Buffer source, long byteCount) throws IOException { | ||
super.write(source, byteCount); | ||
totalBytesWritten += byteCount; | ||
progressListener.update(totalBytesWritten, contentLength(), | ||
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. I think this case is asymmetric with the download case, in that you don't get a call to 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. ... (and the close method calls 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. I know I don't get a
It seems to work without it, is there a case where overriding 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. Yes. Sometimes you don't know content length in advance. |
||
totalBytesWritten == contentLength()); | ||
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. (You can look at the PostStreaming example to see an unknown content length in practice.) |
||
} | ||
}; | ||
} | ||
} | ||
|
||
interface ProgressListener { | ||
void update(long bytesWritten, long contentLength, boolean done); | ||
} | ||
} |
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.
Could you change this so that it wraps another RequestBody? That way the caller can do whatever they want: upload data being generated, a file, or whatever.
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.
I wanted to, but from what I've gathered I can't get the upload data out of the request body, so it would have to look like this,
file
being passed to theRequestBody
and again to theProgressRequestBody
so it can be accessed forcontentLength()
etc.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.
You can, but you need to be a bit sneaky. You'd just need to call
delegate.writeTo(buffer(progressSink(sink)))
in your ownwriteTo
method.