package com.qiniu.android.storage;
import android.util.Log;
import com.qiniu.android.http.Client;
import com.qiniu.android.http.CompletionHandler;
import com.qiniu.android.http.PostArgs;
import com.qiniu.android.http.ProgressHandler;
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.utils.AndroidNetwork;
import com.qiniu.android.utils.Crc32;
import com.qiniu.android.utils.StringMap;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.net.URI;
/**
* 表单上传
* <p/>
* 通过表单,你可以将一个图片或者一个文本文件等上传到七牛服务器。这个表单
* 就是标准的http表单,即<code>enctype="multipart/form-data"</code>
* 格式的表单。
*/
final class FormUploader {
/**
* 上传数据,并以指定的key保存文件
*
* @param httpManager HTTP连接管理器
* @param data 上传的数据
* @param key 上传的数据保存的文件名
* @param token 上传凭证
* @param completionHandler 上传完成后续处理动作
* @param options 上传时的可选参数
*/
static void upload(Client httpManager, Configuration config, byte[] data, String key, UpToken token, final UpCompletionHandler completionHandler,
final UploadOptions options) {
post(data, null, key, token, completionHandler, options, httpManager, config);
}
/**
* 上传文件,并以指定的key保存文件
*
* @param client HTTP连接管理器
* @param file 上传的文件
* @param key 上传的数据保存的文件名
* @param token 上传凭证
* @param completionHandler 上传完成后续处理动作
* @param options 上传时的可选参数
*/
static void upload(Client client, Configuration config, File file, String key, UpToken token, UpCompletionHandler completionHandler,
UploadOptions options) {
post(null, file, key, token, completionHandler, options, client, config);
}
private static void post(byte[] data, File file, String k, final UpToken token, final UpCompletionHandler completionHandler,
final UploadOptions optionsIn, final Client client, final Configuration config) {
final String key = k;
StringMap params = new StringMap();
final PostArgs args = new PostArgs();
if (k != null) {
params.put("key", key);
args.fileName = key;
} else {
args.fileName = "?";
}
// data is null , or file is null
if (file != null) {
args.fileName = file.getName();
}
params.put("token", token.token);
final UploadOptions options = optionsIn != null ? optionsIn : UploadOptions.defaultOptions();
params.putFileds(options.params);
if (options.checkCrc) {
long crc = 0;
if (file != null) {
try {
crc = Crc32.file(file);
} catch (IOException e) {
e.printStackTrace();
}
} else {
crc = Crc32.bytes(data);
}
params.put("crc32", "" + crc);
}
final ProgressHandler progress = new ProgressHandler() {
@Override
public void onProgress(int bytesWritten, int totalSize) {
double percent = (double) bytesWritten / (double) totalSize;
if (percent > 0.95) {
percent = 0.95;
}
options.progressHandler.progress(key, percent);
}
};
args.data = data;
args.file = file;
args.mimeType = options.mimeType;
args.params = params;
final String upHost = config.zone.upHost(token.token, config.useHttps, null);
Log.d("Qiniu.FormUploader", "upload use up host " + upHost);
CompletionHandler completion = new CompletionHandler() {
@Override
public void complete(ResponseInfo info, JSONObject response) {
if (info.isNetworkBroken() && !AndroidNetwork.isNetWorkReady()) {
options.netReadyHandler.waitReady();
if (!AndroidNetwork.isNetWorkReady()) {
completionHandler.complete(key, info, response);
return;
}
}
if (info.isOK()) {
options.progressHandler.progress(key, 1.0);
completionHandler.complete(key, info, response);
} else if (options.cancellationSignal.isCancelled()) {
ResponseInfo i = ResponseInfo.cancelled(token);
completionHandler.complete(key, i, null);
} else if (info.needRetry() || (info.isNotQiniu() && !token.hasReturnUrl())) {
final String upHostRetry = config.zone.upHost(token.token, config.useHttps, upHost);
Log.d("Qiniu.FormUploader", "retry upload first time use up host " + upHostRetry);
CompletionHandler retried = new CompletionHandler() {
@Override
public void complete(ResponseInfo info, JSONObject response) {
if (info.isOK()) {
options.progressHandler.progress(key, 1.0);
completionHandler.complete(key, info, response);
} else if (info.needRetry() || (info.isNotQiniu() && !token.hasReturnUrl())) {
final String upHostRetry2 = config.zone.upHost(token.token, config.useHttps, upHostRetry);
Log.d("Qiniu.FormUploader", "retry upload second time use up host " + upHostRetry2);
CompletionHandler retried2 = new CompletionHandler() {
@Override
public void complete(ResponseInfo info2, JSONObject response2) {
if (info2.isOK()) {
options.progressHandler.progress(key, 1.0);
} else if (info2.needRetry() || (info2.isNotQiniu() && !token.hasReturnUrl())) {
config.zone.frozenDomain(upHostRetry2);
}
completionHandler.complete(key, info2, response2);
}
};
client.asyncMultipartPost(upHostRetry2, args, token, progress, retried2, options.cancellationSignal);
} else {
completionHandler.complete(key, info, response);
}
}
};
client.asyncMultipartPost(upHostRetry, args, token, progress, retried, options.cancellationSignal);
} else {
completionHandler.complete(key, info, response);
}
}
};
client.asyncMultipartPost(upHost, args, token, progress, completion, options.cancellationSignal);
}
/**
* 上传数据,并以指定的key保存文件
*
* @param client HTTP连接管理器
* @param data 上传的数据
* @param key 上传的数据保存的文件名
* @param token 上传凭证
* @param options 上传时的可选参数
* @return 响应信息 ResponseInfo#response 响应体,序列化后 json 格式
*/
public static ResponseInfo syncUpload(Client client, Configuration config, byte[] data, String key, UpToken token, UploadOptions options) {
try {
return syncUpload0(client, config, data, null, key, token, options);
} catch (Exception e) {
return ResponseInfo.create(null, ResponseInfo.UnknownError, "", "", "", "", "", "", 0, 0, 0, e.getMessage(), token);
}
}
/**
* 上传文件,并以指定的key保存文件
*
* @param client HTTP连接管理器
* @param file 上传的文件
* @param key 上传的数据保存的文件名
* @param token 上传凭证
* @param options 上传时的可选参数
* @return 响应信息 ResponseInfo#response 响应体,序列化后 json 格式
*/
public static ResponseInfo syncUpload(Client client, Configuration config, File file, String key, UpToken token, UploadOptions options) {
try {
return syncUpload0(client, config, null, file, key, token, options);
} catch (Exception e) {
return ResponseInfo.create(null, ResponseInfo.UnknownError, "", "", "", "", "", "", 0, 0, 0, e.getMessage(), token);
}
}
private static ResponseInfo syncUpload0(Client client, Configuration config, byte[] data, File file,
String key, UpToken token, UploadOptions optionsIn) {
StringMap params = new StringMap();
final PostArgs args = new PostArgs();
if (key != null) {
params.put("key", key);
args.fileName = key;
} else {
args.fileName = "?";
}
// data is null , or file is null
if (file != null) {
args.fileName = file.getName();
}
params.put("token", token.token);
final UploadOptions options = optionsIn != null ? optionsIn : UploadOptions.defaultOptions();
params.putFileds(options.params);
if (options.checkCrc) {
long crc = 0;
if (file != null) {
try {
crc = Crc32.file(file);
} catch (IOException e) {
e.printStackTrace();
}
} else {
crc = Crc32.bytes(data);
}
params.put("crc32", "" + crc);
}
args.data = data;
args.file = file;
args.mimeType = options.mimeType;
args.params = params;
boolean success = config.zone.preQuery(token.token);
if (!success) {
return ResponseInfo.invalidToken("failed to get up host");
}
final String upHost = config.zone.upHost(token.token, config.useHttps, null);
Log.d("Qiniu.FormUploader", "sync upload use up host " + upHost);
ResponseInfo info = client.syncMultipartPost(upHost, args, token);
if (info.isOK()) {
return info;
}
//retry for the first time
if (info.needRetry() || (info.isNotQiniu() && !token.hasReturnUrl())) {
if (info.isNetworkBroken() && !AndroidNetwork.isNetWorkReady()) {
options.netReadyHandler.waitReady();
if (!AndroidNetwork.isNetWorkReady()) {
return info;
}
}
//retry for the second time
String upHostRetry = config.zone.upHost(token.token, config.useHttps, upHost);
Log.d("Qiniu.FormUploader", "sync upload retry first time use up host " + upHostRetry);
info = client.syncMultipartPost(upHostRetry, args, token);
if (info.needRetry() || (info.isNotQiniu() && !token.hasReturnUrl())) {
if (info.isNetworkBroken() && !AndroidNetwork.isNetWorkReady()) {
options.netReadyHandler.waitReady();
if (!AndroidNetwork.isNetWorkReady()) {
return info;
}
}
String upHostRetry2 = config.zone.upHost(token.token, config.useHttps, upHostRetry);
Log.d("Qiniu.FormUploader", "sync upload retry second time use up host " + upHostRetry2);
info = client.syncMultipartPost(upHostRetry2, args, token);
if (info.needRetry() || (info.isNotQiniu() && !token.hasReturnUrl())) {
config.zone.frozenDomain(upHostRetry2);
}
}
}
return info;
}
}