() {
77 | @Override
78 | public boolean enumerate(String s) {
79 | System.out.println("size:" + size + " value:" + s);
80 | return false;
81 | }
82 | });
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/qiniu/android/utils/LogUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import com.qiniu.android.BaseTest;
8 |
9 | import org.junit.Test;
10 | import org.junit.runner.RunWith;
11 |
12 | @RunWith(AndroidJUnit4.class)
13 | public class LogUtilsTest extends BaseTest {
14 |
15 | @Test
16 | public void testLog() {
17 |
18 | LogUtil.enableLog(true);
19 | LogUtil.setLogLevel(Log.VERBOSE);
20 |
21 | Throwable throwable = new Throwable();
22 |
23 | assertTrue(validLogCode(LogUtil.v("log")));
24 | assertTrue(validLogCode(LogUtil.v("v", "log")));
25 | assertTrue(validLogCode(LogUtil.v("v", "log", null)));
26 | assertTrue(validLogCode(LogUtil.v("v", "log", throwable)));
27 |
28 | assertTrue(validLogCode(LogUtil.d("log")));
29 | assertTrue(validLogCode(LogUtil.d("v", "log")));
30 | assertTrue(validLogCode(LogUtil.d("v", "log", null)));
31 | assertTrue(validLogCode(LogUtil.d("v", "log", throwable)));
32 |
33 | assertTrue(validLogCode(LogUtil.i("log")));
34 | assertTrue(validLogCode(LogUtil.i("v", "log")));
35 | assertTrue(validLogCode(LogUtil.i("v", "log", null)));
36 | assertTrue(validLogCode(LogUtil.i("v", "log", throwable)));
37 |
38 | assertTrue(validLogCode(LogUtil.w("log")));
39 | assertTrue(validLogCode(LogUtil.w("v", "log")));
40 | assertTrue(validLogCode(LogUtil.w("v", "log", null)));
41 | assertTrue(validLogCode(LogUtil.w("v", "log", throwable)));
42 |
43 | assertTrue(validLogCode(LogUtil.e("log")));
44 | assertTrue(validLogCode(LogUtil.e("v", "log")));
45 | assertTrue(validLogCode(LogUtil.e("v", "log", null)));
46 | assertTrue(validLogCode(LogUtil.e("v", "log", throwable)));
47 |
48 | LogUtil.enableLog(false);
49 | }
50 |
51 | private boolean validLogCode(int code) {
52 | return !(code == -10000 || code == -10001);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/qiniu/android/utils/NetworkTest.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import static org.junit.Assert.assertTrue;
4 |
5 | import androidx.test.ext.junit.runners.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | /**
11 | * Created by bailong on 16/9/7.
12 | */
13 | @RunWith(AndroidJUnit4.class)
14 | public class NetworkTest {
15 |
16 | @Test
17 | public void testConnected() {
18 | boolean stat = AndroidNetwork.isNetWorkReady();
19 | assertTrue(stat);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/qiniu/android/utils/StringUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4;
4 |
5 | import com.qiniu.android.BaseTest;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | @RunWith(AndroidJUnit4.class)
11 | public class StringUtilsTest extends BaseTest {
12 |
13 | @Test
14 | public void testJoin(){
15 |
16 | String string = "";
17 |
18 | string = StringUtils.join(new String[]{"1", "2"}, "-");
19 | assertTrue(string.equals("1-2"));
20 |
21 | string = StringUtils.jsonJoin(new String[]{"1", "2"});
22 | assertTrue(string.equals("\"1\",\"2\""));
23 |
24 | }
25 |
26 | @Test
27 | public void testTransform(){
28 |
29 | String string = "";
30 |
31 | string = StringUtils.jsonJoin(new Long[]{1L, 2L});
32 | assertTrue(string.equals("\"1\",\"2\""));
33 |
34 | String[] stringArray = StringUtils.longToString(new Long[]{1L, 2L});
35 | assertTrue(stringArray.length == 2);
36 |
37 | string = "1234";
38 | byte[] data = StringUtils.toByteArray(string);
39 | byte[] dataR = new byte[]{-84, -19, 0, 5, 116, 0, 4, 49, 50, 51, 52};
40 | assertTrue(new String(dataR).equals(new String(data)));
41 |
42 | Object stringR = StringUtils.toObject(dataR);
43 | assertTrue(stringR.equals(string));
44 |
45 |
46 | string = "tom";
47 | string = StringUtils.upperCase(string);
48 | assertTrue(string.equals("Tom"));
49 | }
50 |
51 | @Test
52 | public void testToken(){
53 | String token = "jH983zIUFIP1OVumiBVGeAfiLYJvwrF45S-t22eu:mWEhowqz4sG301DXU6CB3IO7Zss=:eyJzY29wZSI6InpvbmUxLXNwYWNlIiwiZGVhZGxpbmUiOjE1OTczOTMzOTYsICJyZXR1cm5Cb2R5Ijoie1wiZm9vXCI6JCh4OmZvbyksIFwiYmFyXCI6JCh4OmJhciksIFwibWltZVR5cGVcIjokKG1pbWVUeXBlKSwgXCJoYXNoXCI6JChldGFnKSwgXCJrZXlcIjokKGtleSksIFwiZm5hbWVcIjokKGZuYW1lKX0ifQ==";
54 | String ak = StringUtils.getAkAndScope(token);
55 | assertTrue(ak.equals("jH983zIUFIP1OVumiBVGeAfiLYJvwrF45S-t22euzone1-space"));
56 |
57 | String bucket = StringUtils.getBucket(token);
58 | assertTrue(bucket.equals("zone1-space"));
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/qiniu/android/utils/UtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4;
4 |
5 | import com.qiniu.android.BaseTest;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | @RunWith(AndroidJUnit4.class)
11 | public class UtilsTest extends BaseTest {
12 |
13 | @Test
14 | public void testIPType(){
15 |
16 | String testHost = "host";
17 | String type = "";
18 |
19 | type = Utils.getIpType("10.10.120.3", testHost);
20 | assertTrue(type.equals(testHost + "-10-10"));
21 |
22 | type = Utils.getIpType("130.101.120.3", testHost);
23 | assertTrue(type.equals(testHost + "-130-101"));
24 |
25 | type = Utils.getIpType("2000:0000:0000:0000:0001:2345:6789:abcd", testHost);
26 | assertTrue(type.equals(testHost + "-ipv6-2000-0000-0000-0000"));
27 |
28 | type = Utils.getIpType("2000:0:0:0:0001:2345:6789:abcd", testHost);
29 | assertTrue(type.equals(testHost + "-ipv6-2000-0000-0000-0000"));
30 |
31 | type = Utils.getIpType("2000::0001:2345:6789:abcd", testHost);
32 | assertTrue(type.equals(testHost + "-ipv6-2000-0000-0000-0000"));
33 | }
34 |
35 | @Test
36 | public void testIsIPType(){
37 |
38 | String ip = null;
39 | boolean isIpv6 = false;
40 |
41 | ip = "10.10.120.3";
42 | isIpv6 = Utils.isIpv6(ip);
43 | assertFalse(ip, isIpv6);
44 |
45 | ip = "130.101.120.3";
46 | isIpv6 = Utils.isIpv6(ip);
47 | assertFalse(ip, isIpv6);
48 |
49 | ip = "2000:0000:0000:0000:0001:2345:6789:abcd";
50 | isIpv6 = Utils.isIpv6(ip);
51 | assertTrue(ip, isIpv6);
52 |
53 | ip = "2000:0:0:0:0001:2345:6789:abcd";
54 | isIpv6 = Utils.isIpv6(ip);
55 | assertTrue(ip, isIpv6);
56 |
57 | ip = "2000::0001:2345:6789:abcd";
58 | isIpv6 = Utils.isIpv6(ip);
59 | assertTrue(ip, isIpv6);
60 |
61 | ip = "0::0";
62 | isIpv6 = Utils.isIpv6(ip);
63 | assertTrue(ip, isIpv6);
64 |
65 | ip = "ffff::ffff:2345:6789:abcd";
66 | isIpv6 = Utils.isIpv6(ip);
67 | assertTrue(ip, isIpv6);
68 |
69 | ip = "ff1::ffff:2345:6789:abcd";
70 | isIpv6 = Utils.isIpv6(ip);
71 | assertTrue(ip, isIpv6);
72 |
73 | ip = "ffff1::ffff:2345:6789:abcd";
74 | isIpv6 = Utils.isIpv6(ip);
75 | assertFalse(ip, isIpv6);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
16 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/bigdata/Configuration.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.bigdata;
2 |
3 | import com.qiniu.android.http.ProxyConfiguration;
4 |
5 | /**
6 | * Created by long on 2017/7/25.
7 | *
8 | * @hidden
9 | */
10 |
11 | public final class Configuration implements Cloneable {
12 |
13 | /**
14 | * pipelineHost
15 | */
16 | public String pipelineHost = "https://pipeline.qiniu.com";
17 |
18 | /**
19 | * 请求 proxy
20 | */
21 | public ProxyConfiguration proxy;
22 |
23 |
24 | /**
25 | * 连接超时时间,单位 秒
26 | */
27 | public int connectTimeout = 3;
28 |
29 | /**
30 | * 服务器响应超时时间 单位 秒
31 | */
32 | public int responseTimeout = 10;
33 |
34 | /**
35 | * 构造函数
36 | */
37 | public Configuration() {
38 | }
39 |
40 | /**
41 | * Configuration copy
42 | *
43 | * @param config 待 copy 对象
44 | * @return Configuration
45 | */
46 | public static Configuration copy(Configuration config) {
47 | if (config == null) {
48 | return new Configuration();
49 | }
50 | try {
51 | return config.clone();
52 | } catch (CloneNotSupportedException e) {
53 | return new Configuration();
54 | }
55 | }
56 |
57 | /**
58 | * Configuration clone
59 | *
60 | * @return Configuration
61 | */
62 | public Configuration clone() throws CloneNotSupportedException {
63 | return (Configuration) super.clone();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/bigdata/client/CompletionHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.bigdata.client;
2 |
3 | import com.qiniu.android.http.ResponseInfo;
4 |
5 | import org.json.JSONObject;
6 |
7 | /**
8 | * 定义请求完成后续动作的处理接口
9 | *
10 | * @hidden
11 | */
12 | public interface CompletionHandler {
13 | /**
14 | * 用户自定义的处理对象必须实现的接口方法
15 | *
16 | * @param info 响应的调试信息
17 | * @param response 响应的数据
18 | */
19 | void complete(ResponseInfo info, JSONObject response);
20 | }
21 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/bigdata/client/PostArgs.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.bigdata.client;
2 |
3 | import com.qiniu.android.utils.StringMap;
4 |
5 | import java.io.File;
6 |
7 | /**
8 | * 定义请求参数列表
9 | *
10 | * @hidden
11 | */
12 | public final class PostArgs {
13 | /**
14 | * 上传的数据
15 | */
16 | public byte[] data;
17 | /**
18 | * 上传的文件
19 | */
20 | public File file;
21 | /**
22 | * 请求参数
23 | */
24 | public StringMap params;
25 | /**
26 | * 上传文件名
27 | */
28 | public String fileName;
29 | /**
30 | * 上传文件或数据的MimeType
31 | */
32 | public String mimeType;
33 |
34 | /**
35 | * 构造函数
36 | */
37 | public PostArgs() {
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/collect/ReportConfig.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.collect;
2 |
3 | import com.qiniu.android.common.Config;
4 | import com.qiniu.android.utils.Utils;
5 |
6 | /**
7 | * 记录配置
8 | */
9 | public class ReportConfig {
10 |
11 | /**
12 | * 是否开启sdk上传信息搜集 默认为YES
13 | */
14 | public boolean isReportEnable;
15 |
16 | /**
17 | * 每次上传时间间隔 单位:分钟 默认为0.5分钟
18 | */
19 | public double interval;
20 |
21 | /**
22 | * 记录文件大于 uploadThreshold 会触发上传,单位:字节 默认为16 * 1024
23 | */
24 | public long uploadThreshold;
25 |
26 | /**
27 | * 记录文件最大值 要大于 uploadThreshold 单位:字节 默认为4 * 1024 * 1024
28 | */
29 | public long maxRecordFileSize;
30 |
31 | /**
32 | * 记录文件所在文件夹目录
33 | */
34 | public final String recordDirectory;
35 |
36 | /**
37 | * 信息上报服务器地址
38 | */
39 | public final String serverURL;
40 |
41 | /**
42 | * 信息上报请求超时时间 单位:秒 默认为10秒
43 | */
44 | public int timeoutInterval;
45 |
46 | private static ReportConfig instance = new ReportConfig();
47 |
48 | private ReportConfig() {
49 | this.isReportEnable = Config.isRecord;
50 | this.interval = Config.interval;
51 | this.serverURL = Config.upLogURL;
52 | if (Config.recordDir != null) {
53 | this.recordDirectory = Config.recordDir;
54 | } else {
55 | this.recordDirectory = Utils.sdkDirectory() + "/report";
56 | }
57 | this.maxRecordFileSize = Config.maxRecordFileSize;
58 | this.uploadThreshold = Config.uploadThreshold;
59 | this.timeoutInterval = 10;
60 | }
61 |
62 | /**
63 | * 获取配置单例
64 | *
65 | * @return 配置单例
66 | */
67 | public static ReportConfig getInstance() {
68 | return instance;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/common/Config.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.common;
2 |
3 | import com.qiniu.android.utils.ContextGetter;
4 |
5 | /**
6 | * Created by Simon on 11/22/16.
7 | */
8 | public final class Config {
9 |
10 | /**
11 | * 上传信息收集文件的地址 只保留域名部分 eg:uplog.qbox.me
12 | */
13 | public final static String upLogURL = "uplog.qbox.me";
14 |
15 | /**
16 | * 是否记录上传状态信息。 true 表示记录,false 表示不记录。
17 | *
18 | * 记录上传信息条件:
19 | * isRecord 为 true,
20 | * 记录文件大小 小于 maxRecordFileSize .
21 | *
22 | * 记录文件大小 大于 maxRecordFileSize 时, 则暂停记录信息。
23 | */
24 | public static boolean isRecord = true;
25 |
26 | /**
27 | * 是否上传记录的上传状态信息。true 表示上传,false 表示不上传。
28 | *
29 | * 上传条件:
30 | * 增加一条上传记录时触发,
31 | * isRecord 为 true, isUpload 为 true,
32 | * 且 记录文件大小 大于 uploadThreshold,
33 | * 且 距上次上传时间大于 minInteval .
34 | *
35 | * 上传成功后,清空记录文件文件
36 | */
37 | public static boolean isUpload = true;
38 |
39 | /**
40 | * 上传信息记录文件保存的目录, 绝对路径。
41 | * 默认使用当前应用的缓存目录: getCacheDir()
42 | */
43 | public static String recordDir = null;
44 |
45 |
46 | static {
47 | try {
48 | recordDir = ContextGetter.applicationContext().getCacheDir().getAbsolutePath();
49 | } catch (Throwable e) {
50 | e.fillInStackTrace();
51 | }
52 | }
53 |
54 | /**
55 | * 记录上传信息文件最大值,单位:字节。
56 | *
57 | * 记录文件大于此值后暂停记录上传信息。
58 | */
59 | public static int maxRecordFileSize = 4 * 1024 * 1024;
60 |
61 | /**
62 | * 记录文件大于 uploadThreshold 后才可能触发上传,单位:字节。
63 | * 可依据客户上传频率、文件大小做调整
64 | */
65 | public static int uploadThreshold = 16 * 1024;
66 |
67 | /**
68 | * 每次上传最小时间间隔.单位:分钟
69 | */
70 | public static double interval = 0.5;
71 |
72 | /**
73 | * preQuery host
74 | */
75 | public static String preQueryHost00 = "uc.qiniuapi.com";
76 |
77 | /**
78 | * preQuery host
79 | */
80 | public static String preQueryHost01 = "kodo-config.qiniuapi.com";
81 |
82 | /**
83 | * preQuery host
84 | */
85 | public static String preQueryHost02 = "uc.qbox.me";
86 |
87 | /**
88 | * preQuery host
89 | */
90 | @Deprecated
91 | public static String preQueryHost03 = "api.qiniu.com";
92 |
93 | /**
94 | * 获取 preQuery hosts
95 | *
96 | * @return preQuery hosts
97 | */
98 | public static String[] preQueryHosts() {
99 | return new String[]{preQueryHost00, preQueryHost01, preQueryHost02};
100 | }
101 |
102 | /**
103 | * 当网络切换到 wifi 下,切换到此设置
104 | */
105 | public static void quick() {
106 | uploadThreshold = 1 * 1024;
107 | interval = 2;
108 | }
109 |
110 | /**
111 | * 标准设置
112 | */
113 | public static void normal() {
114 | uploadThreshold = 16 * 1024;
115 | interval = 10;
116 | }
117 |
118 | /**
119 | * 网络走流量时,可切换到此设置
120 | */
121 | public static void slow() {
122 | uploadThreshold = 150 * 1024;
123 | interval = 300;
124 | }
125 |
126 | private Config() {
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/common/Constants.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.common;
2 |
3 |
4 | /**
5 | * 常量定义
6 | */
7 | public final class Constants {
8 |
9 | /**
10 | * SDK 版本号
11 | */
12 | public static final String VERSION = "8.8.0";
13 |
14 | /**
15 | * UTF-8 编码
16 | */
17 | public static final String UTF_8 = "utf-8";
18 |
19 | private Constants() {
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/common/Zone.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.common;
2 |
3 | import com.qiniu.android.http.ResponseInfo;
4 | import com.qiniu.android.http.metrics.UploadRegionRequestMetrics;
5 | import com.qiniu.android.storage.Configuration;
6 | import com.qiniu.android.storage.UpToken;
7 |
8 | /**
9 | * Created by bailong on 15/10/10.
10 | */
11 | public abstract class Zone {
12 |
13 | /**
14 | * 构造函数
15 | */
16 | protected Zone() {
17 | }
18 |
19 | /**
20 | * 根据上传 token 获取 zone
21 | *
22 | * @param token 上传 token
23 | * @return 区域信息
24 | */
25 | public abstract ZonesInfo getZonesInfo(UpToken token);
26 |
27 | /**
28 | * 根据上传 token 对区域进行预查询
29 | *
30 | * @param token 上传 token
31 | * @param completeHandler 预查询结束回调
32 | */
33 | @Deprecated
34 | public abstract void preQuery(UpToken token, QueryHandler completeHandler);
35 |
36 | /**
37 | * 根据上传 token 对区域进行预查询
38 | *
39 | * @param configuration 配置信息
40 | * @param token 上传 token
41 | * @param completeHandler 预查询结束回调
42 | */
43 | public abstract void query(Configuration configuration, UpToken token, final QueryHandlerV2 completeHandler);
44 |
45 | /**
46 | * 预查询结束回调
47 | */
48 | public interface QueryHandler {
49 | /**
50 | * 预查询结束回调
51 | *
52 | * @param code 状态码
53 | * @param responseInfo 查询响应
54 | * @param metrics 查询指标
55 | */
56 | void complete(int code, ResponseInfo responseInfo, UploadRegionRequestMetrics metrics);
57 | }
58 |
59 | /**
60 | * 预查询结束回调
61 | */
62 | public interface QueryHandlerV2 {
63 | /**
64 | * 预查询结束回调
65 | *
66 | * @param responseInfo 查询响应
67 | * @param metrics 查询指标
68 | * @param zonesInfo 区域信息
69 | */
70 | void complete(ResponseInfo responseInfo, UploadRegionRequestMetrics metrics, ZonesInfo zonesInfo);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/CancellationHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * 取消对调定义
7 | */
8 | public interface CancellationHandler {
9 |
10 | /**
11 | * 定义用户取消数据或文件上传的信号
12 | *
13 | * @return 是否已取消
14 | */
15 | boolean isCancelled();
16 |
17 | /**
18 | * 取消异常
19 | */
20 | class CancellationException extends IOException {
21 |
22 | /**
23 | * 构造函数
24 | */
25 | public CancellationException() {
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/ProgressHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http;
2 |
3 | /**
4 | * 定义进度处理接口
5 | */
6 | public interface ProgressHandler {
7 | /**
8 | * 用户自定义进度处理对象必须实现的接口方法
9 | *
10 | * @param bytesWritten 已经写入字节
11 | * @param totalSize 总字节数
12 | */
13 | void onProgress(long bytesWritten, long totalSize);
14 | }
15 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/ProxyConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.net.Proxy;
6 |
7 | import okhttp3.Authenticator;
8 | import okhttp3.Credentials;
9 | import okhttp3.Route;
10 |
11 | /**
12 | * http 代理
13 | */
14 | public final class ProxyConfiguration {
15 |
16 | /**
17 | * hostAddress
18 | */
19 | public final String hostAddress;
20 |
21 | /**
22 | * port
23 | */
24 | public final int port;
25 |
26 | /**
27 | * user
28 | */
29 | public final String user;
30 |
31 | /**
32 | * password
33 | */
34 | public final String password;
35 |
36 | /**
37 | * type
38 | */
39 | public final Proxy.Type type;
40 |
41 | /**
42 | * 构造函数
43 | *
44 | * @param hostAddress 服务器域名或IP,比如proxy.com, 192.168.1.1
45 | * @param port 端口
46 | * @param user 用户名,无则填null
47 | * @param password 用户密码,无则填null
48 | * @param type proxy type
49 | */
50 | public ProxyConfiguration(String hostAddress, int port, String user, String password, java.net.Proxy.Type type) {
51 | this.hostAddress = hostAddress;
52 | this.port = port;
53 | this.user = user;
54 | this.password = password;
55 | this.type = type;
56 | }
57 |
58 | /**
59 | * 构造函数
60 | *
61 | * @param hostAddress 服务器域名或IP,比如proxy.com, 192.168.1.1
62 | * @param port 端口
63 | */
64 | public ProxyConfiguration(String hostAddress, int port) {
65 | this(hostAddress, port, null, null, Proxy.Type.HTTP);
66 | }
67 |
68 | /**
69 | * 获取 proxy
70 | *
71 | * @return proxy
72 | */
73 | public Proxy proxy() {
74 | return new Proxy(type, new InetSocketAddress(hostAddress, port));
75 | }
76 |
77 | /**
78 | * 获取 authenticator
79 | *
80 | * @return Authenticator
81 | */
82 | public Authenticator authenticator() {
83 | return new Authenticator() {
84 | @Override
85 | public okhttp3.Request authenticate(Route route, okhttp3.Response response) throws IOException {
86 | String credential = Credentials.basic(user, password);
87 | return response.request().newBuilder().
88 | header("Proxy-Authorization", credential).
89 | header("Proxy-Connection", "Keep-Alive").build();
90 | }
91 | };
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/UrlConverter.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http;
2 |
3 | /**
4 | * url 拦截器
5 | */
6 | public interface UrlConverter {
7 |
8 | /**
9 | * url 拦截器,可以转换 url
10 | *
11 | * @param url url
12 | * @return 转换后的 url
13 | */
14 | String convert(String url);
15 | }
16 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/UserAgent.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http;
2 |
3 | import android.os.Build;
4 | import android.text.TextUtils;
5 |
6 | import com.qiniu.android.common.Constants;
7 | import com.qiniu.android.utils.StringUtils;
8 | import com.qiniu.android.utils.Utils;
9 |
10 | import java.nio.charset.Charset;
11 | import java.util.Locale;
12 | import java.util.Random;
13 |
14 | import static java.lang.String.format;
15 |
16 | /**
17 | * Created by bailong on 15/6/23.
18 | *
19 | * @hidden
20 | */
21 | public final class UserAgent {
22 | private static UserAgent _instance = new UserAgent();
23 |
24 | /**
25 | * id
26 | */
27 | public final String id;
28 |
29 | /**
30 | * UserAgent
31 | */
32 | public final String ua;
33 |
34 | private UserAgent() {
35 | id = genId();
36 | ua = getUserAgent(id);
37 | }
38 |
39 | /**
40 | * 获取 UserAgent 单例
41 | *
42 | * @return UserAgent 单例
43 | */
44 | public static UserAgent instance() {
45 | return _instance;
46 | }
47 |
48 | private static String genId() {
49 | Random r = new Random();
50 | return System.currentTimeMillis() + "" + r.nextInt(999);
51 | }
52 |
53 | static String getUserAgent(String id) {
54 | String addition = Utils.isDebug() ? "_Debug" : "";
55 | return format("QiniuAndroid%s/%s (%s; %s; %s", addition, Constants.VERSION,
56 | Utils.systemVersion(), Utils.systemName(), id);
57 | }
58 |
59 | /**
60 | * 获取 UserAgent 字符串
61 | *
62 | * @param part part
63 | * @return UserAgent 字符串
64 | */
65 | public String getUa(String part) {
66 | String _part = ("" + part).trim();
67 | if (_part.length() > 15) {
68 | _part = _part.substring(0, Math.min(16, _part.length()));
69 | }
70 | return new String((ua + "; " + _part + ")").getBytes(Charset.forName("ISO-8859-1")));
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/BaseDns.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import java.util.concurrent.ExecutorService;
4 | import java.util.concurrent.LinkedBlockingQueue;
5 | import java.util.concurrent.ThreadPoolExecutor;
6 | import java.util.concurrent.TimeUnit;
7 |
8 | class BaseDns {
9 | int timeout = 10;
10 | static final ExecutorService executor = new ThreadPoolExecutor(0, 4,
11 | 60L, TimeUnit.SECONDS, new LinkedBlockingQueue());
12 | }
13 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/Dns.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import java.net.UnknownHostException;
4 | import java.util.List;
5 |
6 | /**
7 | * Dns 解析器
8 | *
9 | * Created by sxci on 03/04/2018.
10 | */
11 | public interface Dns {
12 |
13 | /**
14 | * Dns 解析 host 域名
15 | *
16 | * @param hostname host 域名
17 | * @return 解析结果
18 | * @throws UnknownHostException 异常信息
19 | */
20 | List lookup(String hostname) throws UnknownHostException;
21 | }
22 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/DnsCacheFile.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import com.qiniu.android.storage.Recorder;
4 |
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 |
10 | /**
11 | * Created by jemy on 2019/9/17.
12 | *
13 | * @hidden
14 | */
15 |
16 | public class DnsCacheFile implements Recorder {
17 |
18 | /**
19 | * dns 缓存路径
20 | */
21 | public String directory;
22 |
23 | /**
24 | * dns 缓存文件句柄
25 | */
26 | public File f;
27 |
28 | /**
29 | * DnsCacheFile 构造函数
30 | *
31 | * @param directory dns 缓存路径
32 | * @throws IOException 异常信息
33 | */
34 | public DnsCacheFile(String directory) throws IOException {
35 | if (directory == null) {
36 | throw new IOException("directory invalid");
37 | }
38 |
39 | this.directory = directory;
40 | f = new File(directory);
41 |
42 | if (!f.exists()) {
43 | boolean r = f.mkdirs();
44 | if (!r) {
45 | throw new IOException("mkdir failed");
46 | }
47 | }
48 |
49 | if (!f.isDirectory()) {
50 | throw new IOException("does not mkdir");
51 | }
52 | }
53 |
54 | /**
55 | * 设置DNS缓存
56 | *
57 | * @param key 缓存文件明
58 | * @param data 缓存数据
59 | */
60 | @Override
61 | public synchronized void set(String key, byte[] data) {
62 | File f = new File(directory, key);
63 | if (f.exists()) {
64 | f.delete();
65 | }
66 |
67 | FileOutputStream fo = null;
68 | try {
69 | fo = new FileOutputStream(f);
70 | fo.write(data);
71 | } catch (IOException e) {
72 | e.printStackTrace();
73 | }
74 | if (fo != null) {
75 | try {
76 | fo.close();
77 | } catch (IOException e) {
78 | e.printStackTrace();
79 | }
80 | }
81 | }
82 |
83 | /**
84 | * 获取缓存
85 | *
86 | * @param key 缓存文件名
87 | */
88 | @Override
89 | public synchronized byte[] get(String key) {
90 | File f = new File(directory, key);
91 | if (!f.exists()) {
92 | return null;
93 | }
94 |
95 | FileInputStream fi = null;
96 | byte[] data = null;
97 | int read = 0;
98 | try {
99 | data = new byte[(int) f.length()];
100 | fi = new FileInputStream(f);
101 | read = fi.read(data);
102 | } catch (IOException e) {
103 | e.printStackTrace();
104 | }
105 | if (fi != null) {
106 | try {
107 | fi.close();
108 | } catch (IOException e) {
109 | e.printStackTrace();
110 | }
111 | }
112 | if (read == 0) {
113 | return null;
114 | }
115 | return data;
116 | }
117 |
118 | //f.delete()=false时才会有fs.length>1的情况
119 | public String getFileName() {
120 | return "dnsCache";
121 | }
122 |
123 | @Override
124 | public synchronized void del(String key) {
125 | if (key != null) {
126 | File f = new File(directory, key);
127 | f.delete();
128 | }
129 | }
130 |
131 | synchronized void clearCache() throws IOException {
132 | if (f == null) {
133 | throw new IOException("directory invalid");
134 | }
135 |
136 | File[] subFiles = f.listFiles();
137 | if (subFiles != null && subFiles.length > 0) {
138 | for (File f : subFiles) {
139 | f.delete();
140 | }
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/DnsNetworkAddress.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import com.qiniu.android.storage.GlobalConfiguration;
4 | import com.qiniu.android.utils.Utils;
5 |
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | class DnsNetworkAddress implements IDnsNetworkAddress, java.io.Serializable {
10 |
11 | private final String hostValue;
12 | private final String ipValue;
13 | private final Long ttlValue;
14 | private final String sourceValue;
15 | private final Long timestampValue;
16 |
17 | static DnsNetworkAddress address(JSONObject jsonObject){
18 | String hostValue = null;
19 | String ipValue = null;
20 | Long ttlValue = null;
21 | String sourceValue = null;
22 | Long timestampValue = null;
23 | try {
24 | hostValue = jsonObject.getString("hostValue");
25 | } catch (JSONException e) {}
26 | try {
27 | ipValue = jsonObject.getString("ipValue");
28 | } catch (JSONException e) {}
29 | try {
30 | ttlValue = jsonObject.getLong("ttlValue");
31 | } catch (JSONException e) {}
32 | try {
33 | timestampValue = jsonObject.getLong("timestampValue");
34 | } catch (JSONException e) {}
35 | try {
36 | sourceValue = jsonObject.getString("sourceValue");
37 | } catch (JSONException e) {}
38 |
39 | DnsNetworkAddress networkAddress = new DnsNetworkAddress(hostValue, ipValue, ttlValue, sourceValue, timestampValue);
40 | return networkAddress;
41 | }
42 |
43 | DnsNetworkAddress(String hostValue,
44 | String ipValue,
45 | Long ttlValue,
46 | String sourceValue,
47 | Long timestampValue) {
48 | this.hostValue = hostValue;
49 | this.ipValue = ipValue;
50 | this.ttlValue = ttlValue;
51 | this.sourceValue = sourceValue;
52 | this.timestampValue = timestampValue;
53 | }
54 |
55 | JSONObject toJson(){
56 | JSONObject jsonObject = new JSONObject();
57 | try {
58 | jsonObject.put("hostValue", this.hostValue);
59 | } catch (JSONException e) {}
60 | try {
61 | jsonObject.put("ipValue", this.ipValue);
62 | } catch (JSONException e) {}
63 | try {
64 | jsonObject.put("ttlValue", this.ttlValue);
65 | } catch (JSONException e) {}
66 | try {
67 | jsonObject.put("timestampValue", this.timestampValue);
68 | } catch (JSONException e) {}
69 | try {
70 | jsonObject.put("sourceValue", this.sourceValue);
71 | } catch (JSONException e) {}
72 | return jsonObject;
73 | }
74 |
75 | @Override
76 | public String getHostValue() {
77 | return hostValue;
78 | }
79 |
80 | @Override
81 | public String getIpValue() {
82 | return ipValue;
83 | }
84 |
85 | @Override
86 | public Long getTtlValue() {
87 | return ttlValue;
88 | }
89 |
90 | @Override
91 | public String getSourceValue() {
92 | return sourceValue;
93 | }
94 |
95 | @Override
96 | public Long getTimestampValue() {
97 | return timestampValue;
98 | }
99 |
100 | boolean isValid() {
101 | if (timestampValue == null || ipValue == null || ipValue.length() == 0) {
102 | return false;
103 | }
104 | int maxTTL = GlobalConfiguration.getInstance().dnsCacheMaxTTL;
105 | return (Utils.currentTimestamp() / 1000) < timestampValue + maxTTL;
106 | }
107 |
108 | boolean needRefresh() {
109 | if (timestampValue == null || ttlValue == null || ipValue == null || ipValue.length() == 0) {
110 | return false;
111 | }
112 | int ttl = ttlValue.intValue();
113 | return (Utils.currentTimestamp() / 1000) > timestampValue + ttl;
114 | }
115 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/DnsSource.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | /**
4 | * Dns 解析源
5 | */
6 | public class DnsSource {
7 |
8 | /**
9 | * Doh 解析源
10 | */
11 | public static final String Doh = "doh";
12 |
13 | /**
14 | * udp 方式的解析源
15 | */
16 | public static final String Udp = "dns";
17 |
18 | /**
19 | * DnsPod 解析源
20 | */
21 | public static final String Dnspod = "dnspod";
22 |
23 | /**
24 | * System 解析源
25 | */
26 | public static final String System = "system";
27 |
28 | /**
29 | * 自定义解析源
30 | */
31 | public static final String Custom = "customized";
32 |
33 | /**
34 | * 未知解析源
35 | */
36 | public static final String None = "none";
37 |
38 | private DnsSource() {
39 | }
40 |
41 | /**
42 | * 判断解析源是否为 Doh
43 | *
44 | * @param source 解析源
45 | * @return 解析源是否为 Doh
46 | */
47 | public static boolean isDoh(String source) {
48 | return source != null && source.contains(Doh);
49 | }
50 |
51 | /**
52 | * 判断解析源是否为 Udp
53 | *
54 | * @param source 解析源
55 | * @return 解析源是否为 Udp
56 | */
57 | public static boolean isUdp(String source) {
58 | return source != null && source.contains(Udp);
59 | }
60 |
61 | /**
62 | * 判断解析源是否为 DnsPod
63 | *
64 | * @param source 解析源
65 | * @return 解析源是否为 DnsPod
66 | */
67 | public static boolean isDnspod(String source) {
68 | return source != null && source.contains(Dnspod);
69 | }
70 |
71 | /**
72 | * 判断解析源是否为系统的
73 | *
74 | * @param source 解析源
75 | * @return 解析源是否为系统的
76 | */
77 | public static boolean isSystem(String source) {
78 | return source != null && source.contains(System);
79 | }
80 |
81 | /**
82 | * 判断解析源是否为自定义的
83 | *
84 | * @param source 解析源
85 | * @return 解析源是否为自定义的
86 | */
87 | public static boolean isCustom(String source) {
88 | return source != null && source.contains(Custom);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/HappyDns.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import com.qiniu.android.dns.DnsManager;
4 | import com.qiniu.android.storage.GlobalConfiguration;
5 |
6 | import java.io.IOException;
7 | import java.net.UnknownHostException;
8 | import java.util.List;
9 |
10 | /**
11 | * Created by yangsen on 2020/6/8
12 | *
13 | * @hidden
14 | */
15 | @Deprecated
16 | public class HappyDns implements Dns {
17 |
18 | private Dns customDns;
19 | private SystemDns systemDns;
20 |
21 | private DnsQueryErrorHandler errorHandler;
22 |
23 | /**
24 | * 构造函数
25 | */
26 | public HappyDns() {
27 | int dnsTimeout = GlobalConfiguration.getInstance().dnsResolveTimeout;
28 | systemDns = new SystemDns(dnsTimeout);
29 | customDns = GlobalConfiguration.getInstance().dns;
30 | }
31 |
32 | void setQueryErrorHandler(DnsQueryErrorHandler handler) {
33 | errorHandler = handler;
34 | }
35 |
36 | @Override
37 | public List lookup(String hostname) throws UnknownHostException {
38 | List addressList = null;
39 | int dnsTimeout = GlobalConfiguration.getInstance().dnsResolveTimeout;
40 | // 自定义 dns
41 | if (customDns != null) {
42 | try {
43 | addressList = customDns.lookup(hostname);
44 | } catch (IOException e) {
45 | handleDnsError(e, hostname);
46 | }
47 | if (addressList != null && addressList.size() > 0) {
48 | return addressList;
49 | }
50 | }
51 |
52 | // 系统 dns
53 | try {
54 | addressList = systemDns.lookup(hostname);
55 | } catch (IOException e) {
56 | handleDnsError(e, hostname);
57 | }
58 | if (addressList != null && addressList.size() > 0) {
59 | return addressList;
60 | }
61 |
62 | // http dns
63 | try {
64 | HttpDns httpDns = new HttpDns(dnsTimeout);
65 | addressList = httpDns.lookup(hostname);
66 | } catch (IOException e) {
67 | handleDnsError(e, hostname);
68 | }
69 | if (addressList != null && addressList.size() > 0) {
70 | return addressList;
71 | }
72 |
73 | // udp dns
74 | try {
75 | UdpDns udpDns = new UdpDns(dnsTimeout);
76 | addressList = udpDns.lookup(hostname);
77 | } catch (IOException e) {
78 | handleDnsError(e, hostname);
79 | }
80 |
81 | return addressList;
82 | }
83 |
84 | private void handleDnsError(IOException e, String host) {
85 | if (errorHandler != null) {
86 | errorHandler.queryError(e, host);
87 | }
88 | }
89 |
90 | interface DnsQueryErrorHandler extends DnsManager.QueryErrorHandler {
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/HttpDns.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import com.qiniu.android.dns.Domain;
4 | import com.qiniu.android.dns.IResolver;
5 | import com.qiniu.android.dns.Record;
6 | import com.qiniu.android.dns.dns.DohResolver;
7 | import com.qiniu.android.storage.GlobalConfiguration;
8 |
9 | import java.io.IOException;
10 | import java.net.UnknownHostException;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.concurrent.ExecutorService;
14 | import java.util.concurrent.LinkedBlockingQueue;
15 | import java.util.concurrent.ThreadPoolExecutor;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | /**
19 | * Http Dns
20 | *
21 | * @hidden
22 | */
23 | public class HttpDns extends BaseDns implements Dns {
24 |
25 | private IResolver httpIpv4Resolver;
26 | private IResolver httpIpv6Resolver;
27 |
28 | /**
29 | * 构造函数
30 | *
31 | * @param timeout 解析超时时间
32 | */
33 | public HttpDns(int timeout) {
34 | String[] dohIpv4Servers = GlobalConfiguration.getInstance().getDohIpv4Servers();
35 | if (dohIpv4Servers != null && dohIpv4Servers.length > 0) {
36 | httpIpv4Resolver = new DohResolver(dohIpv4Servers, Record.TYPE_A, timeout, executor);
37 | }
38 |
39 | String[] dohIpv6Servers = GlobalConfiguration.getInstance().getDohIpv6Servers();
40 | if (dohIpv6Servers != null && dohIpv6Servers.length > 0) {
41 | httpIpv6Resolver = new DohResolver(dohIpv6Servers, Record.TYPE_A, timeout, executor);
42 | }
43 | }
44 |
45 | /**
46 | * Dns 解析函数
47 | *
48 | * @param hostname host 域名
49 | * @return 解析结果
50 | * @throws UnknownHostException 异常
51 | */
52 | @Override
53 | public List lookup(String hostname) throws UnknownHostException {
54 | if (!GlobalConfiguration.getInstance().dohEnable) {
55 | return null;
56 | }
57 |
58 | if (httpIpv4Resolver == null && httpIpv6Resolver == null) {
59 | throw new UnknownHostException("resolver server is invalid");
60 | }
61 |
62 | Record[] records = null;
63 | if (httpIpv4Resolver != null) {
64 | try {
65 | records = httpIpv4Resolver.resolve(new Domain(hostname), null);
66 | } catch (IOException ignore) {
67 | }
68 | }
69 |
70 | if ((records == null || records.length == 0) && httpIpv6Resolver != null) {
71 | try {
72 | records = httpIpv6Resolver.resolve(new Domain(hostname), null);
73 | } catch (IOException ignore) {
74 | }
75 | }
76 |
77 | if (records == null || records.length == 0) {
78 | return null;
79 | }
80 |
81 | ArrayList addressList = new ArrayList<>();
82 | for (Record record : records) {
83 | if (record.isA() || record.isAAAA()) {
84 | String source = DnsSource.Doh + ":<" + record.server + ">";
85 | DnsNetworkAddress address = new DnsNetworkAddress(hostname, record.value, record.timeStamp, source, record.timeStamp);
86 | addressList.add(address);
87 | }
88 | }
89 |
90 | return addressList;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/IDnsNetworkAddress.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 |
4 | /**
5 | * Dns 预解析信息
6 | *
7 | * @hidden
8 | */
9 | public interface IDnsNetworkAddress {
10 |
11 | /**
12 | * 预解析的域名
13 | *
14 | * @return 预解析的域名
15 | */
16 | String getHostValue();
17 |
18 | /**
19 | * 预解析域名的 IP 信息
20 | *
21 | * @return 预解析域名的 IP 信息
22 | */
23 | String getIpValue();
24 |
25 | /**
26 | * 预解析域名的 IP 有效时间 单位:秒
27 | *
28 | * @return 预解析域名的 IP 有效时间
29 | */
30 | Long getTtlValue();
31 |
32 | /**
33 | * 预解析的源,自定义dns返回 "customized"
34 | *
35 | * @return 预解析的源
36 | */
37 | String getSourceValue();
38 |
39 | /**
40 | * 解析到 host 时的时间戳,单位:秒
41 | *
42 | * @return 解析到 host 时的时间戳
43 | */
44 | Long getTimestampValue();
45 | }
46 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/SystemDns.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import com.qiniu.android.storage.GlobalConfiguration;
4 |
5 | import java.net.InetAddress;
6 | import java.net.UnknownHostException;
7 | import java.util.ArrayList;
8 | import java.util.Arrays;
9 | import java.util.Date;
10 | import java.util.List;
11 | import java.util.concurrent.Callable;
12 | import java.util.concurrent.ExecutorService;
13 | import java.util.concurrent.Future;
14 | import java.util.concurrent.FutureTask;
15 | import java.util.concurrent.LinkedBlockingQueue;
16 | import java.util.concurrent.ThreadPoolExecutor;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | * Created by yangsen on 2020/5/28
21 | *
22 | * @hidden
23 | */
24 | public class SystemDns extends BaseDns implements Dns {
25 |
26 | /**
27 | * 构造函数
28 | */
29 | public SystemDns() {
30 | }
31 |
32 | /**
33 | * 构造函数
34 | *
35 | * @param timeout DNS 解析超时时间
36 | */
37 | public SystemDns(int timeout) {
38 | this.timeout = timeout;
39 | }
40 |
41 | /**
42 | * DNS 解析域名
43 | *
44 | * @param hostname 域名
45 | * @return 解析结果
46 | * @throws UnknownHostException 异常
47 | */
48 | public List lookupInetAddress(final String hostname) throws UnknownHostException {
49 | if (hostname == null) {
50 | throw new UnknownHostException("hostname is null");
51 | } else {
52 | try {
53 | Future> task = executor.submit(new Callable>() {
54 | @Override
55 | public List call() throws Exception {
56 | return Arrays.asList(InetAddress.getAllByName(hostname));
57 | }
58 | });
59 | return task.get(timeout, TimeUnit.SECONDS);
60 | } catch (Exception var4) {
61 | UnknownHostException unknownHostException =
62 | new UnknownHostException("dns broken when lookup of " + hostname);
63 | unknownHostException.initCause(var4);
64 | throw unknownHostException;
65 | }
66 | }
67 | }
68 |
69 | /**
70 | * DNS 解析域名
71 | *
72 | * @param hostname 域名
73 | * @return 解析结果
74 | * @throws UnknownHostException 异常
75 | */
76 | @Override
77 | public List lookup(String hostname) throws UnknownHostException {
78 | long timestamp = new Date().getTime() / 1000;
79 | long defaultTTL = GlobalConfiguration.getInstance().dnsCacheTime;
80 | ArrayList addressList = new ArrayList<>();
81 | List inetAddressList = lookupInetAddress(hostname);
82 | for (InetAddress inetAddress : inetAddressList) {
83 | DnsNetworkAddress address = new DnsNetworkAddress(inetAddress.getHostName(), inetAddress.getHostAddress(), defaultTTL, DnsSource.System, timestamp);
84 | addressList.add(address);
85 | }
86 | return addressList;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/dns/UdpDns.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.dns;
2 |
3 | import com.qiniu.android.dns.Domain;
4 | import com.qiniu.android.dns.IResolver;
5 | import com.qiniu.android.dns.Record;
6 | import com.qiniu.android.dns.dns.DnsUdpResolver;
7 | import com.qiniu.android.storage.GlobalConfiguration;
8 |
9 | import java.io.IOException;
10 | import java.net.UnknownHostException;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.concurrent.ExecutorService;
14 | import java.util.concurrent.LinkedBlockingQueue;
15 | import java.util.concurrent.ThreadPoolExecutor;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | /**
19 | * udp dns
20 | *
21 | * @hidden
22 | */
23 | public class UdpDns extends BaseDns implements Dns {
24 | private IResolver udpIpv4Resolver;
25 | private IResolver udpIpv6Resolver;
26 |
27 | /**
28 | * 构造函数
29 | *
30 | * @param timeout 超时时间,单位:秒
31 | */
32 | public UdpDns(int timeout) {
33 | String[] udpIpv4Servers = GlobalConfiguration.getInstance().getUdpDnsIpv4Servers();
34 | if (udpIpv4Servers != null && udpIpv4Servers.length > 0) {
35 | udpIpv4Resolver = new DnsUdpResolver(udpIpv4Servers, Record.TYPE_A, timeout, executor);
36 | }
37 |
38 | String[] udpIpv6Servers = GlobalConfiguration.getInstance().getUdpDnsIpv6Servers();
39 | if (udpIpv6Servers != null && udpIpv6Servers.length > 0) {
40 | udpIpv6Resolver = new DnsUdpResolver(udpIpv6Servers, Record.TYPE_A, timeout, executor);
41 | }
42 | }
43 |
44 | /**
45 | * 解析域名
46 | *
47 | * @param hostname host 域名
48 | * @return 解析结果
49 | * @throws UnknownHostException 异常
50 | */
51 | @Override
52 | public List lookup(String hostname) throws UnknownHostException {
53 | if (!GlobalConfiguration.getInstance().udpDnsEnable) {
54 | return null;
55 | }
56 |
57 | if (udpIpv4Resolver == null && udpIpv6Resolver == null) {
58 | throw new UnknownHostException("resolver server is invalid");
59 | }
60 |
61 | Record[] records = null;
62 | if (udpIpv4Resolver != null) {
63 | try {
64 | records = udpIpv4Resolver.resolve(new Domain(hostname), null);
65 | } catch (IOException ignore) {
66 | }
67 | }
68 |
69 | if ((records == null || records.length == 0) && udpIpv6Resolver != null) {
70 | try {
71 | records = udpIpv6Resolver.resolve(new Domain(hostname), null);
72 | } catch (IOException ignore) {
73 | }
74 | }
75 |
76 | if (records == null || records.length == 0) {
77 | return null;
78 | }
79 |
80 | ArrayList addressList = new ArrayList<>();
81 | for (Record record : records) {
82 | if (record.isA() || record.isAAAA()) {
83 | String source = DnsSource.Udp + ":<" + record.server + ">";
84 | DnsNetworkAddress address = new DnsNetworkAddress(hostname, record.value, record.timeStamp, source, record.timeStamp);
85 | addressList.add(address);
86 | }
87 | }
88 |
89 | return addressList;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/metrics/UploadMetrics.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.metrics;
2 |
3 | import com.qiniu.android.utils.Utils;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * 上传指标
9 | *
10 | * @hidden
11 | */
12 | public class UploadMetrics {
13 |
14 | /**
15 | * 开始时间
16 | */
17 | protected Date startDate = null;
18 |
19 | /**
20 | * 结束时间
21 | */
22 | protected Date endDate = null;
23 |
24 | /**
25 | * 构造函数
26 | */
27 | protected UploadMetrics() {
28 | }
29 |
30 | /**
31 | * 开始
32 | */
33 | public void start() {
34 | startDate = new Date();
35 | }
36 |
37 | /**
38 | * 结束
39 | */
40 | public void end() {
41 | endDate = new Date();
42 | }
43 |
44 | /**
45 | * 获取开始时间
46 | *
47 | * @return 开始时间
48 | */
49 | public Date getStartDate() {
50 | return startDate;
51 | }
52 |
53 | /**
54 | * 获取总耗时
55 | *
56 | * @return 总耗时
57 | */
58 | public long totalElapsedTime() {
59 | if (startDate == null || endDate == null) {
60 | return 0;
61 | }
62 | return Utils.dateDuration(startDate, endDate);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/metrics/UploadRegionRequestMetrics.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.metrics;
2 |
3 | import com.qiniu.android.http.request.IUploadRegion;
4 | import com.qiniu.android.utils.Utils;
5 |
6 | import java.util.Date;
7 | import java.util.List;
8 | import java.util.concurrent.CopyOnWriteArrayList;
9 |
10 | /**
11 | * 区域上传事务
12 | *
13 | * @hidden
14 | */
15 | public class UploadRegionRequestMetrics extends UploadMetrics {
16 |
17 | /**
18 | * 上传区域
19 | */
20 | public final IUploadRegion region;
21 |
22 | private List metricsList = new CopyOnWriteArrayList<>();
23 |
24 | /**
25 | * 构造函数
26 | *
27 | * @param region 上传区域
28 | */
29 | public UploadRegionRequestMetrics(IUploadRegion region) {
30 | this.region = region;
31 | }
32 |
33 | /**
34 | * 请求的次数
35 | *
36 | * @return 请求的次数
37 | */
38 | public Integer requestCount() {
39 | return metricsList.size();
40 | }
41 |
42 | /**
43 | * 发送数据的大小
44 | *
45 | * @return 发送数据的大小
46 | */
47 | public Long bytesSend() {
48 | if (metricsList.isEmpty()) {
49 | return 0L;
50 | }
51 | long bytes = 0;
52 | for (UploadSingleRequestMetrics metrics : metricsList) {
53 | if (metrics != null) {
54 | bytes += metrics.bytesSend();
55 | }
56 | }
57 | return bytes;
58 | }
59 |
60 | /**
61 | * 获取最后一个请求指标
62 | *
63 | * @return 最后一个请求指标
64 | */
65 | public UploadSingleRequestMetrics lastMetrics() {
66 | int size = metricsList.size();
67 | return size < 1 ? null : metricsList.get(size - 1);
68 | }
69 |
70 | /**
71 | * 添加新的上传请求指标
72 | *
73 | * @param metricsList 新的上传请求指标
74 | */
75 | public void addMetricsList(List metricsList) {
76 | if (metricsList == null || metricsList.size() == 0) {
77 | return;
78 | }
79 | for (UploadSingleRequestMetrics metrics : metricsList) {
80 | if (metrics != null) {
81 | this.metricsList.add(metrics);
82 | }
83 | }
84 | }
85 |
86 | /**
87 | * 添加新的上传请求指标
88 | *
89 | * @param metrics 新的上传请求指标
90 | */
91 | public void addMetrics(UploadRegionRequestMetrics metrics) {
92 | if (metrics == null || metrics.region == null || metrics.region.getZoneInfo() == null
93 | || metrics.region.getZoneInfo().regionId == null
94 | || region == null || region.getZoneInfo() == null || region.getZoneInfo().regionId == null
95 | || metrics.metricsList == null || metrics.metricsList.size() == 0) {
96 |
97 | return;
98 | }
99 | String thisRegionId = metrics.region.getZoneInfo().getRegionId();
100 | String metricsRegionId = metrics.region.getZoneInfo().getRegionId();
101 | if (thisRegionId.equals(metricsRegionId)) {
102 | // 拼接开始和结束时间,开始时间要最老的,结束时间要最新的
103 | if (startDate != null && metrics.startDate != null && startDate.getTime() > metrics.startDate.getTime()) {
104 | startDate = metrics.startDate;
105 | }
106 | if (endDate != null && metrics.endDate != null && endDate.getTime() < metrics.endDate.getTime()) {
107 | endDate = metrics.endDate;
108 | }
109 |
110 | addMetricsList(metrics.metricsList);
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/networkStatus/NetworkStatusManager.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.networkStatus;
2 |
3 | import com.qiniu.android.utils.Cache;
4 | import com.qiniu.android.utils.Utils;
5 |
6 | import org.json.JSONObject;
7 |
8 |
9 | /**
10 | * 网络状态管理器
11 | *
12 | * @hidden
13 | */
14 | public class NetworkStatusManager {
15 |
16 | private static final NetworkStatusManager networkStatusManager = new NetworkStatusManager();
17 |
18 | private final Cache cache = new Cache.Builder(NetworkStatus.class)
19 | .setVersion("v2")
20 | .setFlushCount(10)
21 | .builder();
22 |
23 | /**
24 | * 获取单例
25 | *
26 | * @return NetworkStatusManager 单例
27 | */
28 | public static NetworkStatusManager getInstance() {
29 | return networkStatusManager;
30 | }
31 |
32 | private NetworkStatusManager() {
33 | }
34 |
35 | /**
36 | * 获取网络状态唯一标识
37 | *
38 | * @param host host
39 | * @param ip ip
40 | * @return 唯一标识
41 | */
42 | @Deprecated
43 | public static String getNetworkStatusType(String host, String ip) {
44 | return Utils.getIpType(ip, host);
45 | }
46 |
47 | /**
48 | * 获取网络状态唯一标识
49 | *
50 | * @param httpVersion httpVersion
51 | * @param host host
52 | * @param ip ip
53 | * @return 唯一标识
54 | */
55 | public static String getNetworkStatusType(String httpVersion, String host, String ip) {
56 | return Utils.getIpType(httpVersion, ip, host);
57 | }
58 |
59 | /**
60 | * 获取网络状态
61 | *
62 | * @param type 网络状态唯一标识
63 | * @return 网络状态
64 | */
65 | public NetworkStatus getNetworkStatus(String type) {
66 | if (type == null || type.isEmpty()) {
67 | return null;
68 | }
69 |
70 | Cache.Object object = cache.cacheForKey(type);
71 | if (object instanceof NetworkStatus) {
72 | return (NetworkStatus) object;
73 | } else {
74 | return new NetworkStatus();
75 | }
76 | }
77 |
78 | /**
79 | * 更新网络状态
80 | *
81 | * @param type 网络状态唯一标识
82 | * @param speed 网速
83 | */
84 | public void updateNetworkStatus(String type, int speed) {
85 | if (type == null || type.isEmpty()) {
86 | return;
87 | }
88 |
89 | NetworkStatus status = new NetworkStatus();
90 | status.speed = speed;
91 | this.cache.cache(type, status, false);
92 | }
93 |
94 | /**
95 | * default speed
96 | */
97 | protected static final int DefaultSpeed = 600;
98 |
99 | /**
100 | * 网络状态
101 | *
102 | * @hidden
103 | */
104 | public static class NetworkStatus implements Cache.Object {
105 |
106 | private int speed = DefaultSpeed;
107 |
108 | /**
109 | * 获取速度
110 | *
111 | * @return 速度
112 | */
113 | public int getSpeed() {
114 | return speed;
115 | }
116 |
117 | /**
118 | * 设置速度
119 | *
120 | * @param speed speed
121 | */
122 | public void setSpeed(int speed) {
123 | this.speed = speed;
124 | }
125 |
126 | private NetworkStatus() {
127 | }
128 |
129 | /**
130 | * 构造函数
131 | *
132 | * @param jsonObject 网络状态 json 数据
133 | */
134 | public NetworkStatus(JSONObject jsonObject) {
135 | if (jsonObject == null) {
136 | return;
137 | }
138 |
139 | try {
140 | this.speed = jsonObject.getInt("speed");
141 | } catch (Exception ignored) {
142 | }
143 | }
144 |
145 | /**
146 | * 获取 json 数据
147 | *
148 | * @return json 数据
149 | */
150 | @Override
151 | public JSONObject toJson() {
152 | JSONObject jsonObject = new JSONObject();
153 | try {
154 | jsonObject.put("speed", speed);
155 | } catch (Exception ignored) {
156 | }
157 | return jsonObject;
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/networkStatus/UploadServerNetworkStatus.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.networkStatus;
2 |
3 | import com.qiniu.android.http.request.IUploadServer;
4 |
5 | /**
6 | * UploadServerNetworkStatus
7 | *
8 | * @hidden
9 | */
10 | public class UploadServerNetworkStatus {
11 |
12 | private UploadServerNetworkStatus() {
13 | }
14 |
15 | /**
16 | * 获取网络状态较好的 server
17 | *
18 | * @param serverA serverA
19 | * @param serverB serverB
20 | * @return 网络状态较好的 server
21 | */
22 | public static IUploadServer getBetterNetworkServer(IUploadServer serverA, IUploadServer serverB) {
23 | return isServerNetworkBetter(serverA, serverB) ? serverA : serverB;
24 | }
25 |
26 | /**
27 | * serverA 网络状态是否较 serverB 好
28 | * 如果两个 Server 网速相同且类别相同优先使用 serverA,类别不同 HTTP/3 较好
29 | *
30 | * @param serverA serverA
31 | * @param serverB serverB
32 | * @return 是否较好
33 | */
34 | public static boolean isServerNetworkBetter(IUploadServer serverA, IUploadServer serverB) {
35 | if (serverA == null) {
36 | return false;
37 | } else if (serverB == null) {
38 | return true;
39 | }
40 |
41 | String serverTypeA = NetworkStatusManager.getNetworkStatusType(serverA.getHttpVersion(), serverA.getHost(), serverA.getIp());
42 | String serverTypeB = NetworkStatusManager.getNetworkStatusType(serverB.getHttpVersion(), serverB.getHost(), serverB.getIp());
43 | if (serverTypeA == null || serverTypeA.length() == 0) {
44 | return false;
45 | } else if (serverTypeB == null || serverTypeB.length() == 0) {
46 | return true;
47 | }
48 |
49 | NetworkStatusManager.NetworkStatus serverStatusA = NetworkStatusManager.getInstance().getNetworkStatus(serverTypeA);
50 | NetworkStatusManager.NetworkStatus serverStatusB = NetworkStatusManager.getInstance().getNetworkStatus(serverTypeB);
51 |
52 | int serverASpeed = serverStatusA.getSpeed();
53 | int serverBSpeed = serverStatusB.getSpeed();
54 | String serverAHttpVersion = serverA.getHttpVersion();
55 | String serverBHttpVersion = serverB.getHttpVersion();
56 | if (serverAHttpVersion == null) {
57 | serverAHttpVersion = "";
58 | }
59 | if (serverBHttpVersion == null) {
60 | serverBHttpVersion = "";
61 | }
62 | if (serverAHttpVersion.equals(IUploadServer.HttpVersion3) && !serverAHttpVersion.equals(serverBHttpVersion)) {
63 | if (serverASpeed < 200 && serverBSpeed == NetworkStatusManager.DefaultSpeed) {
64 | return true;
65 | } else if (serverASpeed > NetworkStatusManager.DefaultSpeed && serverBSpeed > 400) {
66 | return false;
67 | }
68 | } else if (serverBHttpVersion.equals(IUploadServer.HttpVersion3) && !serverAHttpVersion.equals(serverBHttpVersion)) {
69 | if (serverBSpeed < 200 && serverASpeed == NetworkStatusManager.DefaultSpeed) {
70 | return false;
71 | } else if (serverBSpeed > NetworkStatusManager.DefaultSpeed && serverASpeed > 400) {
72 | return true;
73 | }
74 | }
75 | return serverBSpeed <= serverASpeed;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/IRequestClient.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request;
2 |
3 | import com.qiniu.android.http.ProxyConfiguration;
4 | import com.qiniu.android.http.ResponseInfo;
5 | import com.qiniu.android.http.metrics.UploadSingleRequestMetrics;
6 |
7 | import org.json.JSONObject;
8 |
9 | /**
10 | * 请求 Client 抽象
11 | */
12 | public abstract class IRequestClient {
13 |
14 | /**
15 | * 请求进度协议
16 | */
17 | public interface Progress {
18 |
19 | /**
20 | * 请求进度回调
21 | *
22 | * @param totalBytesWritten totalBytesWritten
23 | * @param totalBytesExpectedToWrite totalBytesExpectedToWrite
24 | */
25 | void progress(long totalBytesWritten, long totalBytesExpectedToWrite);
26 | }
27 |
28 | /**
29 | * 请求完成回调
30 | */
31 | public interface CompleteHandler {
32 |
33 | /**
34 | * 请求完成回调
35 | *
36 | * @param responseInfo 请求响应信息
37 | * @param metrics 请求指标
38 | * @param response 请求响应信息
39 | */
40 | void complete(ResponseInfo responseInfo, UploadSingleRequestMetrics metrics, JSONObject response);
41 | }
42 |
43 | /**
44 | * 构造函数
45 | */
46 | protected IRequestClient() {
47 | }
48 |
49 | /**
50 | * 触发请求
51 | *
52 | * @param request 请求信息
53 | * @param options 可选信息
54 | * @param progress 进度回调
55 | * @param complete 完成回调
56 | */
57 | public abstract void request(Request request,
58 | Options options,
59 | Progress progress,
60 | CompleteHandler complete);
61 |
62 | /**
63 | * 取消
64 | */
65 | public abstract void cancel();
66 |
67 | /**
68 | * 获取 ClientId
69 | *
70 | * @return ClientId
71 | */
72 | public String getClientId() {
73 | return "customized";
74 | }
75 |
76 | /**
77 | * 可选信息
78 | */
79 | public static class Options {
80 |
81 | /**
82 | * 上传请求的 Server
83 | */
84 | public final IUploadServer server;
85 |
86 | /**
87 | * 是否使用异步
88 | */
89 | public final boolean isAsync;
90 |
91 | /**
92 | * 请求的代理
93 | */
94 | public final ProxyConfiguration connectionProxy;
95 |
96 | /**
97 | * 构造函数
98 | *
99 | * @param server 上传请求的 Server
100 | * @param isAsync 是否使用异步
101 | * @param connectionProxy 请求的代理
102 | */
103 | public Options(IUploadServer server, boolean isAsync, ProxyConfiguration connectionProxy) {
104 | this.server = server;
105 | this.isAsync = isAsync;
106 | this.connectionProxy = connectionProxy;
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/IUploadRegion.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request;
2 |
3 | import com.qiniu.android.common.ZoneInfo;
4 | import com.qiniu.android.http.ResponseInfo;
5 |
6 | /**
7 | * 上传区域
8 | *
9 | * @hidden
10 | */
11 | public interface IUploadRegion {
12 |
13 | /**
14 | * 是否有效
15 | *
16 | * @return 是否有效
17 | */
18 | boolean isValid();
19 |
20 | /**
21 | * 是否和另一个 region 相等
22 | *
23 | * @param region 另一个 region
24 | * @return 是否和另一个 region 相等
25 | */
26 | boolean isEqual(IUploadRegion region);
27 |
28 | /**
29 | * 获取 ZoneInfo
30 | *
31 | * @return ZoneInfo
32 | */
33 | ZoneInfo getZoneInfo();
34 |
35 | /**
36 | * 配置 ZoneInfo
37 | *
38 | * @param zoneInfo ZoneInfo
39 | */
40 | void setupRegionData(ZoneInfo zoneInfo);
41 |
42 | /**
43 | * 获取下一个上传的 Server 信息
44 | *
45 | * @param requestState 请求状态
46 | * @param responseInfo 请求响应信息
47 | * @param freezeServer 冻结的 Server 信息
48 | * @return 下一个上传的 Server 信息
49 | */
50 | IUploadServer getNextServer(UploadRequestState requestState, ResponseInfo responseInfo, IUploadServer freezeServer);
51 |
52 | /**
53 | * 更新 host 的 IP 缓存信息
54 | *
55 | * @param host host
56 | */
57 | void updateIpListFormHost(String host);
58 | }
59 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/IUploadServer.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request;
2 |
3 |
4 | import java.net.InetAddress;
5 |
6 | /**
7 | * upload server 信息
8 | *
9 | * @hidden
10 | */
11 | public abstract class IUploadServer {
12 |
13 | /**
14 | * HTTP/1.1
15 | */
16 | public static String HttpVersion1 = "http_version_1";
17 |
18 | /**
19 | * HTTP/2
20 | */
21 | public static String HttpVersion2 = "http_version_2";
22 |
23 | /**
24 | * HTTP/3
25 | */
26 | public static String HttpVersion3 = "http_version_3";
27 |
28 | /**
29 | * 构造函数
30 | */
31 | protected IUploadServer() {
32 | }
33 |
34 | /**
35 | * 是否使用 HTTP/3
36 | *
37 | * @return 是否使用 HTTP/3
38 | */
39 | public boolean isHttp3() {
40 | String httpVersion = getHttpVersion();
41 | if (httpVersion == null) {
42 | return false;
43 | }
44 | return httpVersion.equals(IUploadServer.HttpVersion3);
45 | }
46 |
47 | /**
48 | * 是否使用 HTTP/2
49 | *
50 | * @return 是否使用 HTTP/2
51 | */
52 | public boolean isHttp2() {
53 | String httpVersion = getHttpVersion();
54 | if (httpVersion == null) {
55 | return false;
56 | }
57 | return httpVersion.equals(IUploadServer.HttpVersion2);
58 | }
59 |
60 | /**
61 | * 获取 ServerId
62 | *
63 | * @return ServerId
64 | */
65 | public abstract String getServerId();
66 |
67 | /**
68 | * 获取 HttpVersion
69 | *
70 | * @return HttpVersion
71 | */
72 | public abstract String getHttpVersion();
73 |
74 | /**
75 | * 获取 Host
76 | *
77 | * @return Host
78 | */
79 | public abstract String getHost();
80 |
81 | /**
82 | * 获取 IP
83 | *
84 | * @return IP
85 | */
86 | public abstract String getIp();
87 |
88 | /**
89 | * 获取 DNS 解析 Source
90 | *
91 | * @return DNS 解析 Source
92 | */
93 | public abstract String getSource();
94 |
95 | /**
96 | * 获取 DNS 解析时间戳
97 | *
98 | * @return DNS 解析时间戳
99 | */
100 | public abstract Long getIpPrefetchedTime();
101 |
102 | /**
103 | * 获取 DNS 解析信息
104 | *
105 | * @return DNS 解析信息
106 | */
107 | public InetAddress getInetAddress() {
108 | String ip = getIp();
109 | String host = getHost();
110 | if (getHost() == null || ip == null || ip.length() == 0) {
111 | return null;
112 | }
113 |
114 | try {
115 | InetAddress ipAddress = InetAddress.getByName(ip);
116 | return InetAddress.getByAddress(host, ipAddress.getAddress());
117 | } catch (Exception e) {
118 | return null;
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/UploadRequestInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request;
2 |
3 | class UploadRequestInfo {
4 |
5 | static final String RequestTypeUCQuery = "uc_query";
6 | static final String RequestTypeForm = "form";
7 | static final String RequestTypeMkblk = "mkblk";
8 | static final String RequestTypeBput = "bput";
9 | static final String RequestTypeMkfile = "mkfile";
10 | static final String RequestTypeInitParts = "init_parts";
11 | static final String RequestTypeUploadPart = "upload_part";
12 | static final String RequestTypeCompletePart = "complete_part";
13 | static final String RequestTypeUpLog = "uplog";
14 | static final String RequestTypeServerConfig = "server_config";
15 | static final String RequestTypeServerUserConfig = "server_user_config";
16 |
17 | String requestType;
18 | String bucket;
19 | String key;
20 | Long fileOffset;
21 | String targetRegionId;
22 | String currentRegionId;
23 |
24 | boolean shouldReportRequestLog(){
25 | return !requestType.equals(RequestTypeUpLog);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/UploadRequestState.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request;
2 |
3 | /**
4 | * 上传状态
5 | *
6 | * @hidden
7 | */
8 | public class UploadRequestState {
9 |
10 | private boolean couldUseHttp3;
11 | private boolean isUseOldServer;
12 | private boolean isUserCancel;
13 |
14 | /**
15 | * 构造函数
16 | */
17 | public UploadRequestState() {
18 | }
19 |
20 | /**
21 | * 是否可以使用 HTTP/3
22 | *
23 | * @return 是否可以使用 HTTP/3
24 | */
25 | public boolean couldUseHttp3() {
26 | return couldUseHttp3;
27 | }
28 |
29 | void setCouldUseHttp3(boolean couldUseHttp3) {
30 | this.couldUseHttp3 = couldUseHttp3;
31 | }
32 |
33 | boolean isUserCancel() {
34 | return isUserCancel;
35 | }
36 |
37 | void setUserCancel(boolean isUserCancel) {
38 | this.isUserCancel = isUserCancel;
39 | }
40 |
41 | /**
42 | * 是否使用支持 sni 的域名
43 | *
44 | * @return 是否使用支持 sni 的域名
45 | */
46 | public boolean isUseOldServer() {
47 | return isUseOldServer;
48 | }
49 |
50 | /**
51 | * 设置是否使用支持 sni 的域名
52 | *
53 | * @param useOldServer 是否使用支持 sni 的域名
54 | */
55 | public void setUseOldServer(boolean useOldServer) {
56 | isUseOldServer = useOldServer;
57 | }
58 |
59 | /**
60 | * clone
61 | *
62 | * @return clone 后的对象
63 | */
64 | protected UploadRequestState clone() {
65 | UploadRequestState state = new UploadRequestState();
66 | state.isUseOldServer = isUseOldServer;
67 | state.isUserCancel = isUserCancel;
68 | return state;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/handler/CheckCancelHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request.handler;
2 |
3 | /**
4 | * CheckCancelHandler
5 | *
6 | * @hidden
7 | */
8 | public interface CheckCancelHandler {
9 |
10 | /**
11 | * 查看是否取消
12 | *
13 | * @return 是否取消
14 | */
15 | boolean checkCancel();
16 | }
17 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/handler/RequestProgressHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request.handler;
2 |
3 | /**
4 | * 请求进度回调
5 | *
6 | * @hidden
7 | */
8 | public interface RequestProgressHandler {
9 |
10 | /**
11 | * 请求进度回调
12 | *
13 | * @param totalBytesWritten 已发送数据大小
14 | * @param totalBytesExpectedToWrite 总数据大小
15 | */
16 | void progress(long totalBytesWritten, long totalBytesExpectedToWrite);
17 | }
18 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/handler/RequestShouldRetryHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request.handler;
2 |
3 | import com.qiniu.android.http.ResponseInfo;
4 |
5 | import org.json.JSONObject;
6 |
7 | /**
8 | * 请求重试回调
9 | *
10 | * @hidden
11 | */
12 | public interface RequestShouldRetryHandler {
13 |
14 | /**
15 | * 请求重试回调
16 | *
17 | * @param responseInfo 上次请求的响应信息
18 | * @param response 上次请求的响应信息
19 | * @return 是否可以重试
20 | */
21 | boolean shouldRetry(ResponseInfo responseInfo, JSONObject response);
22 | }
23 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/httpclient/ByteBody.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request.httpclient;
2 |
3 | import java.io.IOException;
4 | import java.util.Arrays;
5 |
6 | import okhttp3.MediaType;
7 | import okhttp3.RequestBody;
8 | import okio.BufferedSink;
9 |
10 | /**
11 | * Created by yangsen on 2020/6/10
12 | *
13 | * @hidden
14 | */
15 | public class ByteBody extends RequestBody {
16 |
17 | private static final int SEGMENT_SIZE = 1024 * 16; // okio.Segment.SIZE
18 |
19 | private final MediaType mediaType;
20 | private final byte[] body;
21 |
22 | /**
23 | * 请求体
24 | *
25 | * @param mediaType mediaType
26 | * @param body 请求体 byte 数组
27 | */
28 | public ByteBody(MediaType mediaType, byte[] body) {
29 |
30 | this.mediaType = mediaType;
31 | this.body = body;
32 | }
33 |
34 | @Override
35 | public MediaType contentType() {
36 | return mediaType;
37 | }
38 |
39 | @Override
40 | public long contentLength() throws IOException {
41 | return body.length;
42 | }
43 |
44 | @Override
45 | public void writeTo(BufferedSink bufferedSink) throws IOException {
46 |
47 | int byteOffset = 0;
48 | int byteSize = SEGMENT_SIZE;
49 | while (byteOffset < body.length) {
50 | byteSize = Math.min(byteSize, body.length - byteOffset);
51 | RequestBody requestBody = getRequestBodyWithRange(byteOffset, byteSize);
52 | requestBody.writeTo(bufferedSink);
53 | bufferedSink.flush();
54 |
55 | byteOffset += byteSize;
56 | }
57 | }
58 |
59 |
60 | private RequestBody getRequestBodyWithRange(int location, int size) {
61 | byte[] data = Arrays.copyOfRange(body, location, location + size);
62 | return RequestBody.create(contentType(), data);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/request/httpclient/CountingRequestBody.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.request.httpclient;
2 |
3 | import com.qiniu.android.http.CancellationHandler;
4 | import com.qiniu.android.http.ProgressHandler;
5 | import com.qiniu.android.utils.AsyncRun;
6 |
7 | import java.io.IOException;
8 |
9 | import okhttp3.MediaType;
10 | import okhttp3.RequestBody;
11 | import okio.Buffer;
12 | import okio.BufferedSink;
13 | import okio.ForwardingSink;
14 | import okio.Okio;
15 | import okio.Sink;
16 |
17 | /**
18 | * Created by bailong on 16/1/8.
19 | *
20 | * @hidden
21 | */
22 | public final class CountingRequestBody extends RequestBody {
23 | private static final int SEGMENT_SIZE = 2048; // okio.Segment.SIZE
24 |
25 |
26 | private final RequestBody body;
27 | private final ProgressHandler progress;
28 | private final long totalSize;
29 | private final CancellationHandler cancellationHandler;
30 |
31 | /**
32 | * CountingRequestBody 构造函数
33 | *
34 | * @param body 请求体
35 | * @param progress 请求进度回调
36 | * @param totalSize 请求体总大小
37 | * @param cancellationHandler 取消函数
38 | */
39 | public CountingRequestBody(RequestBody body, ProgressHandler progress, long totalSize,
40 | CancellationHandler cancellationHandler) {
41 | this.body = body;
42 | this.progress = progress;
43 | this.totalSize = totalSize;
44 | this.cancellationHandler = cancellationHandler;
45 | }
46 |
47 | /**
48 | * 获取请求体大小
49 | *
50 | * @return 请求体大小
51 | * @throws IOException 异常
52 | */
53 | @Override
54 | public long contentLength() throws IOException {
55 | return body.contentLength();
56 | }
57 |
58 | /**
59 | * 获取请求 ContentType
60 | *
61 | * @return 请求 ContentType
62 | */
63 | @Override
64 | public MediaType contentType() {
65 | return body.contentType();
66 | }
67 |
68 | /**
69 | * 写入数据
70 | *
71 | * @param sink BufferedSink
72 | * @throws IOException 异常
73 | */
74 | @Override
75 | public void writeTo(BufferedSink sink) throws IOException {
76 | BufferedSink bufferedSink;
77 |
78 | CountingSink countingSink = new CountingSink(sink);
79 | bufferedSink = Okio.buffer(countingSink);
80 |
81 | body.writeTo(bufferedSink);
82 |
83 | bufferedSink.flush();
84 | }
85 |
86 | /**
87 | * 请求进度 Sink
88 | *
89 | * @hidden
90 | */
91 | protected final class CountingSink extends ForwardingSink {
92 |
93 | private int bytesWritten = 0;
94 |
95 | /**
96 | * 构造方法
97 | *
98 | * @param delegate Sink
99 | */
100 | public CountingSink(Sink delegate) {
101 | super(delegate);
102 | }
103 |
104 | /**
105 | * 写入数据
106 | *
107 | * @param source Buffer
108 | * @param byteCount byteCount
109 | * @throws IOException 异常
110 | */
111 | @Override
112 | public void write(Buffer source, long byteCount) throws IOException {
113 | if (cancellationHandler == null && progress == null) {
114 | super.write(source, byteCount);
115 | return;
116 | }
117 | if (cancellationHandler != null && cancellationHandler.isCancelled()) {
118 | throw new CancellationHandler.CancellationException();
119 | }
120 | super.write(source, byteCount);
121 | bytesWritten += byteCount;
122 | if (progress != null) {
123 | AsyncRun.runInMain(new Runnable() {
124 | @Override
125 | public void run() {
126 | progress.onProgress(bytesWritten, totalSize);
127 | }
128 | });
129 | }
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/serverRegion/HttpServerManager.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.serverRegion;
2 |
3 | import com.qiniu.android.utils.Utils;
4 |
5 | import java.util.Locale;
6 | import java.util.concurrent.ConcurrentHashMap;
7 |
8 | /**
9 | * HttpServerManager
10 | *
11 | * @hidden
12 | */
13 | public class HttpServerManager {
14 | private ConcurrentHashMap serversInfo = new ConcurrentHashMap<>();
15 | private final static HttpServerManager manager = new HttpServerManager();
16 |
17 | private HttpServerManager() {
18 | }
19 |
20 | /**
21 | * 单例对象
22 | *
23 | * @return 单例对象
24 | */
25 | public static HttpServerManager getInstance() {
26 | return manager;
27 | }
28 |
29 | /**
30 | * 添加支持 http3 的 Host/ip 组合
31 | *
32 | * @param host 支持 http3 的 Host
33 | * @param ip 支持 http3 Host 对应的 ip
34 | * @param liveDuration 有效时间 单位: 秒
35 | * @return 是否添加
36 | */
37 | public boolean addHttp3Server(String host, String ip, int liveDuration) {
38 | if (host == null || host.length() == 0 || ip == null || ip.length() == 0 || liveDuration < 0) {
39 | return false;
40 | }
41 |
42 | String type = getServerType(host, ip);
43 | long deadline = Utils.currentSecondTimestamp() + liveDuration;
44 | serversInfo.put(type, deadline);
45 | return true;
46 | }
47 |
48 | /**
49 | * Host/ip 组合是否支持 http3
50 | *
51 | * @param host host
52 | * @param ip ip
53 | * @return 是否支持 http3
54 | */
55 | public boolean isServerSupportHttp3(String host, String ip) {
56 | if (host == null || host.length() == 0 || ip == null || ip.length() == 0) {
57 | return false;
58 | }
59 |
60 | boolean support = false;
61 | String type = getServerType(host, ip);
62 | Long deadline = serversInfo.get(type);
63 | if (deadline != null && deadline > Utils.currentSecondTimestamp()) {
64 | support = true;
65 | }
66 | return support;
67 | }
68 |
69 | private String getServerType(String host, String ip) {
70 | return String.format(Locale.ENGLISH, "%s:%s", host, ip);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServer.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.serverRegion;
2 |
3 | import com.qiniu.android.http.request.IUploadServer;
4 |
5 | /**
6 | * 上传服务
7 | *
8 | * @hidden
9 | */
10 | public class UploadServer extends IUploadServer {
11 |
12 | private final String serverId;
13 | private final String host;
14 | private final String ip;
15 | private final String source;
16 | private final Long ipPrefetchedTime;
17 | private String httpVersion;
18 |
19 | /**
20 | * 构造函数
21 | *
22 | * @param serverId server id
23 | * @param host host
24 | * @param ip ip
25 | * @param source dns 解析源
26 | * @param ipPrefetchedTime dns 解析时间
27 | */
28 | public UploadServer(String serverId,
29 | String host,
30 | String ip,
31 | String source,
32 | Long ipPrefetchedTime) {
33 | this.serverId = serverId;
34 | this.host = host;
35 | this.ip = ip;
36 | this.source = source;
37 | this.ipPrefetchedTime = ipPrefetchedTime;
38 | }
39 |
40 | /**
41 | * 获取 server id
42 | *
43 | * @return server id
44 | */
45 | @Override
46 | public String getServerId() {
47 | return this.serverId;
48 | }
49 |
50 | /**
51 | * 获取 HTTP version
52 | *
53 | * @return HTTP version
54 | */
55 | @Override
56 | public String getHttpVersion() {
57 | return httpVersion;
58 | }
59 |
60 | /**
61 | * 配置 HTTP version
62 | *
63 | * @param httpVersion HTTP version
64 | */
65 | public void setHttpVersion(String httpVersion) {
66 | this.httpVersion = httpVersion;
67 | }
68 |
69 | /**
70 | * 获取 IP
71 | *
72 | * @return IP
73 | */
74 | @Override
75 | public String getIp() {
76 | return ip;
77 | }
78 |
79 | /**
80 | * 获取 dns 解析源
81 | *
82 | * @return dns 解析源
83 | */
84 | @Override
85 | public String getSource() {
86 | return source;
87 | }
88 |
89 | /**
90 | * 获取 dns 解析时间
91 | *
92 | * @return dns 解析时间
93 | */
94 | @Override
95 | public Long getIpPrefetchedTime() {
96 | return ipPrefetchedTime;
97 | }
98 |
99 | /**
100 | * 获取服务域名
101 | *
102 | * @return 服务域名
103 | */
104 | @Override
105 | public String getHost() {
106 | return host;
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeManager.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.serverRegion;
2 |
3 | import com.qiniu.android.utils.Utils;
4 |
5 | import java.util.Date;
6 | import java.util.concurrent.ConcurrentHashMap;
7 |
8 | /**
9 | * Created by yangsen on 2020/6/3
10 | *
11 | * @hidden
12 | */
13 | public class UploadServerFreezeManager {
14 |
15 | private ConcurrentHashMap frozenInfo = new ConcurrentHashMap<>();
16 | private final static UploadServerFreezeManager manager = new UploadServerFreezeManager();
17 |
18 | /**
19 | * 构造函数
20 | */
21 | public UploadServerFreezeManager() {
22 | }
23 |
24 | /**
25 | * 获取单例
26 | *
27 | * @return 单例
28 | */
29 | public static UploadServerFreezeManager getInstance() {
30 | return manager;
31 | }
32 |
33 | /**
34 | * 查看 type 是否冻结
35 | *
36 | * @param type type
37 | * @return 是否冻结
38 | */
39 | public boolean isTypeFrozen(String type) {
40 | if (type == null || type.length() == 0) {
41 | return true;
42 | }
43 | boolean isFrozen = true;
44 | UploadServerFreezeItem item = frozenInfo.get(type);
45 | if (item == null || !item.isFrozenByDate(new Date())) {
46 | isFrozen = false;
47 | }
48 | return isFrozen;
49 | }
50 |
51 | /**
52 | * 冻结 type
53 | *
54 | * @param type type
55 | * @param frozenTime 冻结时间
56 | */
57 | public void freezeType(String type, int frozenTime) {
58 | if (type == null || type.length() == 0) {
59 | return;
60 | }
61 | UploadServerFreezeItem item = frozenInfo.get(type);
62 | if (item == null) {
63 | item = new UploadServerFreezeItem(type);
64 | frozenInfo.put(type, item);
65 | }
66 | item.freeze(frozenTime);
67 | }
68 |
69 | /**
70 | * 解冻 type
71 | *
72 | * @param type type
73 | */
74 | public void unfreezeType(String type) {
75 | if (type == null || type.length() == 0) {
76 | return;
77 | }
78 | frozenInfo.remove(type);
79 | }
80 |
81 | private static class UploadServerFreezeItem {
82 | protected final String type;
83 | private Date freezeDate;
84 |
85 | private UploadServerFreezeItem(String type) {
86 | this.type = type;
87 | }
88 |
89 | private synchronized boolean isFrozenByDate(Date date) {
90 | boolean isFrozen = true;
91 | if (freezeDate == null || freezeDate.getTime() < date.getTime()) {
92 | isFrozen = false;
93 | }
94 | return isFrozen;
95 | }
96 |
97 | private synchronized void freeze(int frozenTime) {
98 | freezeDate = new Date(Utils.currentTimestamp() + frozenTime * 1000);
99 | }
100 |
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/http/serverRegion/UploadServerFreezeUtil.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.http.serverRegion;
2 |
3 | import com.qiniu.android.utils.Utils;
4 |
5 | /**
6 | * UploadServerFreezeUtil
7 | *
8 | * @hidden
9 | */
10 | public class UploadServerFreezeUtil {
11 | private final static UploadServerFreezeManager globalHttp3Freezer = new UploadServerFreezeManager();
12 |
13 | private UploadServerFreezeUtil() {
14 | }
15 |
16 | /**
17 | * 获取 HTTP/3 冻结管理单例
18 | *
19 | * @return 单例
20 | */
21 | public static UploadServerFreezeManager globalHttp3Freezer() {
22 | return globalHttp3Freezer;
23 | }
24 |
25 | private final static UploadServerFreezeManager globalHttp2Freezer = new UploadServerFreezeManager();
26 |
27 | /**
28 | * 获取 HTTP/2 冻结管理单例
29 | *
30 | * @return 单例
31 | */
32 | public static UploadServerFreezeManager globalHttp2Freezer() {
33 | return globalHttp2Freezer;
34 | }
35 |
36 | /**
37 | * 查看 type 是否被冻结管理者冻结
38 | *
39 | * @param type type
40 | * @param freezeManagerList 结管理者
41 | * @return 是否冻结
42 | */
43 | public static boolean isTypeFrozenByFreezeManagers(String type, UploadServerFreezeManager[] freezeManagerList) {
44 | if (type == null || type.length() == 0) {
45 | return true;
46 | }
47 | if (freezeManagerList == null || freezeManagerList.length == 0) {
48 | return false;
49 | }
50 |
51 | boolean isFrozen = false;
52 | for (UploadServerFreezeManager freezeManager : freezeManagerList) {
53 | isFrozen = freezeManager.isTypeFrozen(type);
54 | if (isFrozen) {
55 | break;
56 | }
57 | }
58 | return isFrozen;
59 | }
60 |
61 | /**
62 | * 获取 type
63 | *
64 | * @param host host
65 | * @param ip ip
66 | * @return type
67 | */
68 | public static String getFrozenType(String host, String ip) {
69 | String ipType = Utils.getIpType(ip, host);
70 | return String.format("%s-%s", host, ipType);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/ConcurrentResumeUpload.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import com.qiniu.android.utils.GroupTaskThread;
4 | import com.qiniu.android.utils.LogUtil;
5 | import com.qiniu.android.utils.StringUtils;
6 |
7 | class ConcurrentResumeUpload extends PartsUpload {
8 |
9 | private GroupTaskThread groupTaskThread;
10 |
11 | protected ConcurrentResumeUpload(UploadSource source,
12 | String key,
13 | UpToken token,
14 | UploadOptions option,
15 | Configuration config,
16 | Recorder recorder,
17 | String recorderKey,
18 | UpTaskCompletionHandler completionHandler) {
19 | super(source, key, token, option, config, recorder, recorderKey, completionHandler);
20 | }
21 |
22 | @Override
23 | protected int prepareToUpload() {
24 | return super.prepareToUpload();
25 | }
26 |
27 | @Override
28 | protected void uploadRestData(final UploadFileRestDataCompleteHandler completeHandler) {
29 | LogUtil.i("key:" + StringUtils.toNonnullString(key));
30 |
31 | GroupTaskThread.GroupTaskCompleteHandler taskCompleteHandler = new GroupTaskThread.GroupTaskCompleteHandler() {
32 | @Override
33 | public void complete() {
34 | completeHandler.complete();
35 | }
36 | };
37 |
38 | groupTaskThread = new GroupTaskThread(taskCompleteHandler);
39 | for (int i = 0; i < config.concurrentTaskCount; i++) {
40 | groupTaskThread.addTask(new GroupTaskThread.GroupTask() {
41 | @Override
42 | public void run(final GroupTaskThread.GroupTask task) {
43 | performUploadRestData(new UploadFileRestDataCompleteHandler() {
44 | @Override
45 | public void complete() {
46 | task.taskComplete();
47 | }
48 | });
49 | }
50 | });
51 | }
52 |
53 | groupTaskThread.start();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/FormUpload.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import com.qiniu.android.http.ResponseInfo;
4 | import com.qiniu.android.http.request.RequestTransaction;
5 | import com.qiniu.android.http.request.handler.RequestProgressHandler;
6 | import com.qiniu.android.http.metrics.UploadRegionRequestMetrics;
7 | import com.qiniu.android.utils.LogUtil;
8 | import com.qiniu.android.utils.StringUtils;
9 |
10 | import org.json.JSONObject;
11 |
12 | class FormUpload extends BaseUpload {
13 |
14 | private boolean isAsync = true;
15 | private final UpProgress upProgress;
16 | private RequestTransaction uploadTransaction;
17 |
18 | protected FormUpload(byte[] data,
19 | String key,
20 | String fileName,
21 | UpToken token,
22 | UploadOptions option,
23 | Configuration config,
24 | UpTaskCompletionHandler completionHandler) {
25 | super(data, key, fileName, token, option, config, completionHandler);
26 | this.upProgress = new UpProgress(this.option.progressHandler);
27 | }
28 |
29 | @Override
30 | protected void startToUpload() {
31 | super.startToUpload();
32 |
33 | LogUtil.i("key:" + StringUtils.toNonnullString(key) + " form上传");
34 |
35 | uploadTransaction = new RequestTransaction(config, option, getTargetRegion(), getCurrentRegion(), key, token);
36 |
37 | RequestProgressHandler progressHandler = new RequestProgressHandler() {
38 | @Override
39 | public void progress(long totalBytesWritten, long totalBytesExpectedToWrite) {
40 | upProgress.progress(key, totalBytesWritten, totalBytesExpectedToWrite);
41 | }
42 | };
43 | uploadTransaction.uploadFormData(data, fileName, isAsync, progressHandler, new RequestTransaction.RequestCompleteHandler() {
44 | @Override
45 | public void complete(ResponseInfo responseInfo, UploadRegionRequestMetrics requestMetrics, JSONObject response) {
46 | addRegionRequestMetricsOfOneFlow(requestMetrics);
47 |
48 | if (!responseInfo.isOK()) {
49 | if (!switchRegionAndUploadIfNeededWithErrorResponse(responseInfo)) {
50 | completeAction(responseInfo, response);
51 | }
52 | return;
53 | }
54 |
55 | upProgress.notifyDone(key, data.length);
56 | completeAction(responseInfo, response);
57 | }
58 | });
59 | }
60 |
61 | @Override
62 | String getUpType() {
63 | return UploadUpTypeForm;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/KeyGenerator.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import java.io.File;
4 |
5 | /**
6 | * 本地持久化上传纪录key生成工具
7 | */
8 | public interface KeyGenerator {
9 | /**
10 | * 根据服务器的 key 和本地文件名生成持久化纪录的 key
11 | *
12 | * @param key 服务器的 key
13 | * @param file 本地文件名
14 | * @return 持久化上传纪录的 key
15 | */
16 | @Deprecated
17 | String gen(String key, File file);
18 |
19 | /**
20 | * 根据服务器的key和本地文件唯一 ID 生成持久化纪录的key
21 | * 如果开启断点续传功能,请确保持久化纪录的 key 相同的文件一定是同一个
22 | * SDK 断点续传流程:
23 | * 1. 用户调用上传接口上传资源 A
24 | * 2. 根据资源 A 信息调用 {@link KeyGenerator#gen(String, String)} 生成持久化纪录的 key
25 | * 3. 根据生成持久化纪录的 key 获取本地缓存记录,无缓存则直接走新资源上传流程
26 | * 4. 解析缓存记录中的 sourceId 对比当前资源 A 的 sourceId,如果不同则走新资源上传流程
27 | * 5. 对比缓存资源的 size 和待上传资源 A 的 size,如果两个 size 均不为 -1 且不相等,
28 | * 则走新资源上传流程;size 等于 -1 时,资源 A 为 InputStream 且不知道文件流大小,不验证 size
29 | * 6. 断点续传生效,进入断点续传流程
30 | *
31 | * @param key 服务器的key
32 | * @param sourceId 本地文件 ID
33 | * File: fileName + modifyTime
34 | * Uri: fileName + modifyTime
35 | * InputStream: fileName
36 | * @return 持久化上传纪录的key
37 | */
38 | String gen(String key, String sourceId);
39 | }
40 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/NetReadyHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | /**
4 | * Created by bailong on 16/9/7.
5 | *
6 | * @hidden
7 | */
8 | public interface NetReadyHandler {
9 |
10 | /**
11 | * 等待网络正常连接
12 | */
13 | void waitReady();
14 | }
15 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/Recorder.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | /**
4 | * 定义分片上传时纪录上传进度的接口
5 | */
6 | public interface Recorder {
7 |
8 | /**
9 | * 新建或更新文件分片上传的进度
10 | *
11 | * @param key 持久化的键
12 | * @param data 持久化的内容
13 | */
14 | void set(String key, byte[] data);
15 |
16 | /**
17 | * 获取文件分片上传的进度信息
18 | *
19 | * @param key 持久化的键
20 | * @return 对应的信息
21 | */
22 | byte[] get(String key);
23 |
24 | /**
25 | * 删除文件分片上传的进度文件
26 | *
27 | * @param key 持久化的键
28 | */
29 | void del(String key);
30 |
31 | /**
32 | * 获取记录的文件名
33 | *
34 | * @return 记录的文件名
35 | */
36 | String getFileName();
37 | }
38 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UpCancellationSignal.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import com.qiniu.android.http.CancellationHandler;
4 |
5 | /**
6 | * 定义用户取消数据或文件上传的信号
7 | * 用户取消上传时,必须实现的接口
8 | */
9 | public interface UpCancellationSignal extends CancellationHandler {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UpCompletionHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import com.qiniu.android.http.ResponseInfo;
4 |
5 | import org.json.JSONObject;
6 |
7 | /**
8 | * 定义数据或文件上传结束后的处理动作
9 | */
10 | public interface UpCompletionHandler {
11 |
12 | /**
13 | * 用户自定义的内容上传完成后处理动作必须实现的方法
14 | * 建议用户自己处理异常。若未处理,抛出的异常被直接丢弃。
15 | *
16 | * @param key 文件上传保存名称
17 | * @param info 上传完成返回日志信息
18 | * @param response 上传完成的回复内容
19 | */
20 | void complete(String key, ResponseInfo info, JSONObject response);
21 | }
22 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UpProgress.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import com.qiniu.android.utils.AsyncRun;
4 | import com.qiniu.android.utils.LogUtil;
5 |
6 | class UpProgress {
7 |
8 | private long maxProgressUploadBytes = -1;
9 | private long previousUploadBytes = 0;
10 | private final UpProgressHandler handler;
11 |
12 | UpProgress(UpProgressHandler handler) {
13 | this.handler = handler;
14 | }
15 |
16 | public void progress(final String key, long uploadBytes, final long totalBytes) {
17 | if (handler == null || uploadBytes < 0 || (totalBytes > 0 && uploadBytes > totalBytes)) {
18 | return;
19 | }
20 |
21 | if (totalBytes > 0) {
22 | synchronized (this) {
23 | if (this.maxProgressUploadBytes < 0) {
24 | this.maxProgressUploadBytes = (long) (totalBytes * 0.95);
25 | }
26 | }
27 |
28 | if (uploadBytes > this.maxProgressUploadBytes) {
29 | return;
30 | }
31 | }
32 |
33 | synchronized (this) {
34 | if (uploadBytes > this.previousUploadBytes) {
35 | this.previousUploadBytes = uploadBytes;
36 | } else {
37 | // 不大于之前回调百分比,不再回调
38 | return;
39 | }
40 | }
41 |
42 | notify(key, uploadBytes, totalBytes);
43 | }
44 |
45 | public void notifyDone(final String key, final long totalBytes) {
46 | notify(key, totalBytes, totalBytes);
47 | }
48 |
49 | private void notify(final String key, long uploadBytes, final long totalBytes) {
50 | if (handler == null) {
51 | return;
52 | }
53 |
54 | // 不管什么类型 source, 在资源 EOF 时间,均可以获取到文件的大小
55 | if (handler instanceof UpProgressBytesHandler) {
56 | AsyncRun.runInMain(new Runnable() {
57 | @Override
58 | public void run() {
59 | LogUtil.i("key:" + key + " progress uploadBytes:" + uploadBytes + " totalBytes:" + totalBytes);
60 | ((UpProgressBytesHandler) handler).progress(key, uploadBytes, totalBytes);
61 | }
62 | });
63 | return;
64 | }
65 |
66 | if (totalBytes <= 0) {
67 | return;
68 | }
69 |
70 | final double notifyPercent = (double) uploadBytes / (double) totalBytes;
71 | AsyncRun.runInMain(new Runnable() {
72 | @Override
73 | public void run() {
74 | LogUtil.i("key:" + key + " progress:" + notifyPercent);
75 | handler.progress(key, notifyPercent);
76 | }
77 | });
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UpProgressBytesHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | /**
4 | * UpProgressBytesHandler
5 | */
6 | public interface UpProgressBytesHandler extends UpProgressHandler {
7 |
8 | /**
9 | * 用户自定义进度处理类必须实现的方法
10 | * 注:
11 | * 使用此接口,{@link UpProgressHandler#progress(String, double)} 会无效
12 | *
13 | * @param key 上传文件的保存文件名
14 | * @param uploadBytes 已上传大小
15 | * @param totalBytes 总大小;无法获取大小时为 -1
16 | */
17 | void progress(String key, long uploadBytes, long totalBytes);
18 | }
19 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UpProgressHandler.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | /**
4 | * 定义数据或文件上传的进度处理方法
5 | */
6 | public interface UpProgressHandler {
7 |
8 | /**
9 | * 用户自定义进度处理类必须实现的方法
10 | *
11 | * @param key 上传文件的保存文件名
12 | * @param percent 上传进度,取值范围[0, 1.0]
13 | */
14 | void progress(String key, double percent);
15 | }
16 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UploadData.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import org.json.JSONObject;
4 |
5 | class UploadData {
6 |
7 | final long offset;
8 | final int size;
9 | final int index;
10 |
11 | String md5;
12 | String etag;
13 |
14 | private State state;
15 | private long uploadSize = 0;
16 |
17 | byte[] data;
18 |
19 | UploadData(long offset, int size, int index) {
20 | this.offset = offset;
21 | this.size = size;
22 | this.index = index;
23 | this.state = State.NeedToCheck;
24 | this.uploadSize = 0;
25 | }
26 |
27 | static UploadData dataFromJson(JSONObject jsonObject) throws Exception {
28 | if (jsonObject == null) {
29 | return null;
30 | }
31 |
32 | long offset = jsonObject.getLong("offset");
33 | int size = jsonObject.getInt("size");
34 | int index = jsonObject.getInt("index");
35 | String etag = jsonObject.optString("etag");
36 | State state = State.state(jsonObject.getInt("state"));
37 | String md5 = jsonObject.optString("md5");
38 |
39 | UploadData uploadData = new UploadData(offset, size, index);
40 | uploadData.etag = etag;
41 | uploadData.md5 = md5;
42 | uploadData.state = state;
43 | uploadData.uploadSize = 0;
44 | return uploadData;
45 | }
46 |
47 | // 需要上传,但需要检测块信息是否有效
48 | boolean needToUpload() {
49 | switch (state) {
50 | case NeedToCheck:
51 | case WaitToUpload:
52 | return true;
53 | default:
54 | return false;
55 | }
56 | }
57 |
58 | // 是否已经上传
59 | boolean isUploaded() {
60 | return state == State.Complete;
61 | }
62 |
63 | State getState() {
64 | return state;
65 | }
66 |
67 | void updateState(State state) {
68 | switch (state) {
69 | case NeedToCheck:
70 | case WaitToUpload:
71 | case Uploading:
72 | uploadSize = 0;
73 | etag = null;
74 | break;
75 | case Complete:
76 | data = null;
77 | }
78 | this.state = state;
79 | }
80 |
81 | void setUploadSize(long uploadSize) {
82 | this.uploadSize = uploadSize;
83 | }
84 |
85 | long uploadSize() {
86 | return state == State.Complete ? size : uploadSize;
87 | }
88 |
89 | void clearUploadState() {
90 | etag = null;
91 | md5 = null;
92 | state = State.NeedToCheck;
93 | }
94 |
95 | void checkStateAndUpdate() {
96 | if ((state == State.WaitToUpload || state == State.Uploading) && data == null) {
97 | state = State.NeedToCheck;
98 | }
99 | }
100 |
101 | JSONObject toJsonObject() throws Exception {
102 | JSONObject jsonObject = new JSONObject();
103 | jsonObject.putOpt("offset", offset);
104 | jsonObject.putOpt("size", size);
105 | jsonObject.putOpt("index", index);
106 | jsonObject.putOpt("etag", etag);
107 | jsonObject.putOpt("md5", md5);
108 | jsonObject.putOpt("state", state.intValue());
109 | return jsonObject;
110 | }
111 |
112 | enum State {
113 | NeedToCheck, // 需要检测数据
114 | WaitToUpload, // 等待上传
115 | Uploading, // 正在上传
116 | Complete; // 上传结束
117 |
118 | private int intValue() {
119 | return this.ordinal();
120 | }
121 |
122 | private static State state(int value) {
123 | State[] states = State.values();
124 | if (value < 0 || value >= states.length) {
125 | return NeedToCheck;
126 | } else {
127 | return states[value];
128 | }
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UploadInfo.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | import java.io.IOException;
7 |
8 | abstract class UploadInfo {
9 |
10 | private String sourceId;
11 | private long sourceSize = UploadSource.UnknownSourceSize;
12 | protected String fileName = null;
13 |
14 | private UploadSource source;
15 |
16 | UploadInfo(UploadSource source) {
17 | this.source = source;
18 | this.sourceSize = source.getSize();
19 | this.sourceId = source.getId() != null ? source.getId() : "";
20 | }
21 |
22 | void setInfoFromJson(JSONObject jsonObject) {
23 | try {
24 | sourceSize = jsonObject.getLong("sourceSize");
25 | sourceId = jsonObject.optString("sourceId");
26 | } catch (JSONException ignored) {
27 | }
28 | }
29 |
30 | /**
31 | * 是否可以重新加载文件信息,也即是否可以重新读取信息
32 | *
33 | * @return return
34 | */
35 | boolean couldReloadSource() {
36 | return source.couldReloadSource();
37 | }
38 |
39 | /**
40 | * 重新加载文件信息,以便于重新读取
41 | *
42 | * @return 重新加载是否成功
43 | */
44 | boolean reloadSource() {
45 | return source.reloadSource();
46 | }
47 |
48 | /**
49 | * 是否为同一个 UploadInfo
50 | * 同一个:source 相同,上传方式相同
51 | */
52 | boolean isSameUploadInfo(UploadInfo info) {
53 | if (info == null || !sourceId.equals(info.sourceId)) {
54 | return false;
55 | }
56 |
57 | // 检测文件大小,如果能获取到文件大小的话,就进行检测
58 | if (info.sourceSize > UploadSource.UnknownSourceSize &&
59 | sourceSize > UploadSource.UnknownSourceSize &&
60 | info.sourceSize != sourceSize) {
61 | return false;
62 | }
63 |
64 | return true;
65 | }
66 |
67 | /**
68 | * 获取资源 id
69 | *
70 | * @return 资源 id
71 | */
72 | String getSourceId() {
73 | return sourceId;
74 | }
75 |
76 | /**
77 | * 获取资源大小
78 | *
79 | * @return
80 | */
81 | long getSourceSize() {
82 | return source.getSize();
83 | }
84 |
85 | /**
86 | * 数据源是否有效,为空则无效
87 | *
88 | * @return 是否有效
89 | */
90 | boolean hasValidResource() {
91 | return source != null;
92 | }
93 |
94 | /**
95 | * 是否有效
96 | *
97 | * @return 是否有效
98 | */
99 | boolean isValid() {
100 | return hasValidResource();
101 | }
102 |
103 | /**
104 | * 获取已上传数据的大小
105 | *
106 | * @return 已上传数据的大小
107 | */
108 | abstract long uploadSize();
109 |
110 | /**
111 | * 文件内容是否完全上传完毕
112 | *
113 | * @return 是否完全上传完毕
114 | */
115 | abstract boolean isAllUploaded();
116 |
117 | /**
118 | * 清楚上传状态
119 | */
120 | abstract void clearUploadState();
121 |
122 | /**
123 | * 检查文件状态, 主要处理没有 data 但处于上传状态
124 | */
125 | abstract void checkInfoStateAndUpdate();
126 |
127 | /**
128 | * 转 json
129 | *
130 | * @return json
131 | */
132 | JSONObject toJsonObject() {
133 | JSONObject jsonObject = new JSONObject();
134 | try {
135 | jsonObject.put("sourceId", sourceId);
136 | jsonObject.put("sourceSize", getSourceSize());
137 | } catch (JSONException ignore) {
138 | }
139 | return jsonObject;
140 | }
141 |
142 | void close() {
143 | source.close();
144 | }
145 |
146 | byte[] readData(int dataSize, long dataOffset) throws IOException {
147 | if (source == null) {
148 | throw new IOException("file is not exist");
149 | }
150 |
151 | byte[] data = null;
152 | synchronized (source) {
153 | data = source.readData(dataSize, dataOffset);
154 | }
155 | if (data != null && (data.length != dataSize || data.length == 0)) {
156 | sourceSize = dataOffset + data.length;
157 | }
158 | return data;
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UploadSource.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import java.io.IOException;
4 |
5 | abstract class UploadSource {
6 | /**
7 | * 未知大小
8 | */
9 | static final long UnknownSourceSize = -1;
10 |
11 | /**
12 | * 获取资源唯一标识
13 | * 作为断点续传时判断是否为同一资源的依据之一;
14 | * 如果两个资源的 record key 和 资源唯一标识均相同则认为资源为同一资源,断点续传才会生效
15 | * 注:
16 | * 同一资源的数据必须完全相同,否则上传可能会出现异常
17 | *
18 | * @return 资源修改时间
19 | */
20 | abstract String getId();
21 |
22 | /**
23 | * 是否可以重新加载文件信息,也即是否可以重新读取信息
24 | * @return return
25 | */
26 | abstract boolean couldReloadSource();
27 |
28 | /**
29 | * 重新加载文件信息,以便于重新读取
30 | *
31 | * @return 重新加载是否成功
32 | */
33 | abstract boolean reloadSource();
34 |
35 | /**
36 | * 获取资源文件名
37 | * @return 资源文件名
38 | */
39 | abstract String getFileName();
40 |
41 | /**
42 | * 获取资源大小
43 | * 无法获取大小时返回 -1
44 | * 作用:
45 | * 1. 验证资源是否为同一资源
46 | * 2. 计算上传进度
47 | *
48 | * @return 资源大小
49 | */
50 | abstract long getSize();
51 |
52 | /**
53 | * 读取数据
54 | * 1. 返回 byte[] 可能为空,但不会为 null;
55 | * 2. 当 byte[] 大小和 dataSize 不同时,则源数据已经读取结束
56 | * 3. 读取异常时抛出 IOException
57 | * 4. 仅支持串行调用,且 dataOffset 依次递增
58 | *
59 | * @param dataSize 数据大小
60 | * @param dataOffset 数据偏移量
61 | * @return 数据
62 | * @throws IOException 异常
63 | */
64 | abstract byte[] readData(int dataSize, long dataOffset) throws IOException;
65 |
66 | /**
67 | * 关闭流
68 | */
69 | abstract void close();
70 |
71 | /**
72 | * 资源类型
73 | */
74 | abstract String getSourceType();
75 | }
76 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UploadSourceFile.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.io.RandomAccessFile;
6 |
7 | class UploadSourceFile extends UploadSource {
8 |
9 | private Exception readException = null;
10 | private final File file;
11 | private final RandomAccessFile randomAccessFile;
12 |
13 | UploadSourceFile(File file) {
14 | this.file = file;
15 | RandomAccessFile randomAccessFile = null;
16 | try {
17 | randomAccessFile = new RandomAccessFile(file, "r");
18 | } catch (Exception e) {
19 | readException = e;
20 | }
21 | this.randomAccessFile = randomAccessFile;
22 | }
23 |
24 | @Override
25 | public String getId() {
26 | return getFileName() + "_" + file.lastModified();
27 | }
28 |
29 | @Override
30 | public boolean couldReloadSource() {
31 | return randomAccessFile != null;
32 | }
33 |
34 | @Override
35 | public boolean reloadSource() {
36 | return true;
37 | }
38 |
39 | @Override
40 | public String getFileName() {
41 | return file.getName();
42 | }
43 |
44 | @Override
45 | public long getSize() {
46 | return file.length();
47 | }
48 |
49 | @Override
50 | public byte[] readData(int dataSize, long dataOffset) throws IOException {
51 | if (randomAccessFile == null) {
52 | if (readException != null) {
53 | throw new IOException(readException);
54 | } else {
55 | throw new IOException("file is invalid");
56 | }
57 | }
58 |
59 | int readSize = 0;
60 | byte[] buffer = new byte[dataSize];
61 | try {
62 | randomAccessFile.seek(dataOffset);
63 | while (readSize < dataSize) {
64 | int ret = randomAccessFile.read(buffer, readSize, (dataSize - readSize));
65 | if (ret < 0) {
66 | break;
67 | }
68 | readSize += ret;
69 | }
70 |
71 | if (readSize < dataSize) {
72 | byte[] newBuffer = new byte[readSize];
73 | System.arraycopy(buffer, 0, newBuffer, 0, readSize);
74 | buffer = newBuffer;
75 | }
76 | } catch (IOException e) {
77 | throw new IOException(e.getMessage());
78 | }
79 | return buffer;
80 | }
81 |
82 | @Override
83 | public void close() {
84 | if (randomAccessFile != null) {
85 | try {
86 | randomAccessFile.close();
87 | } catch (IOException e) {
88 | try {
89 | randomAccessFile.close();
90 | } catch (IOException ignored) {
91 | }
92 | }
93 | }
94 | }
95 |
96 | @Override
97 | String getSourceType() {
98 | return "File";
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/UploadSourceStream.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage;
2 |
3 | import com.qiniu.android.utils.StringUtils;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | class UploadSourceStream extends UploadSource {
8 |
9 | private long readOffset = 0;
10 |
11 | private InputStream inputStream;
12 | private String id;
13 | private boolean hasSize = false;
14 | private long size = UploadSource.UnknownSourceSize;
15 | private String fileName;
16 |
17 | UploadSourceStream(InputStream inputStream) {
18 | this.inputStream = inputStream;
19 | }
20 |
21 | protected InputStream getInputStream() {
22 | return inputStream;
23 | }
24 |
25 | protected void setInputStream(InputStream inputStream) {
26 | this.inputStream = inputStream;
27 | }
28 |
29 |
30 | void setId(String id) {
31 | this.id = id;
32 | }
33 |
34 | @Override
35 | public String getId() {
36 | return !StringUtils.isNullOrEmpty(id) ? id : fileName;
37 | }
38 |
39 | public void setFileName(String fileName) {
40 | this.fileName = fileName;
41 | }
42 |
43 | @Override
44 | public String getFileName() {
45 | return fileName;
46 | }
47 |
48 | @Override
49 | public long getSize() {
50 | if (size > UnknownSourceSize) {
51 | return size;
52 | } else {
53 | return UnknownSourceSize;
54 | }
55 | }
56 |
57 | void setSize(long size) {
58 | this.hasSize = size > 0;
59 | this.size = size;
60 | }
61 |
62 | @Override
63 | public boolean couldReloadSource() {
64 | return false;
65 | }
66 |
67 | @Override
68 | public boolean reloadSource() {
69 | readOffset = 0;
70 | return false;
71 | }
72 |
73 | @Override
74 | public byte[] readData(int dataSize, long dataOffset) throws IOException {
75 | if (inputStream == null) {
76 | throw new IOException("inputStream is empty");
77 | }
78 |
79 | byte[] buffer = null;
80 | synchronized (this) {
81 | boolean isEOF = false;
82 | while (true) {
83 | if (readOffset == dataOffset) {
84 | int readSize = 0;
85 | buffer = new byte[dataSize];
86 | while (readSize < dataSize) {
87 | int ret = inputStream.read(buffer, readSize, dataSize - readSize);
88 | if (ret < 0) {
89 | isEOF = true;
90 | break;
91 | }
92 | readSize += ret;
93 | }
94 |
95 | if (readSize < dataSize) {
96 | byte[] newBuffer = new byte[readSize];
97 | System.arraycopy(buffer, 0, newBuffer, 0, readSize);
98 | buffer = newBuffer;
99 | }
100 |
101 | readOffset += readSize;
102 | if (isEOF) {
103 | size = readOffset;
104 | }
105 | break;
106 | } else if (readOffset < dataOffset) {
107 | readOffset += inputStream.skip(dataOffset - readOffset);
108 | } else {
109 | throw new IOException("read stream data error");
110 | }
111 | }
112 | }
113 | return buffer;
114 | }
115 |
116 | @Override
117 | public void close() {
118 | }
119 |
120 | @Override
121 | String getSourceType() {
122 | return hasSize ? "Stream:HasSize" : "Stream:NoSize";
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/serverConfig/ServerConfigCache.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage.serverConfig;
2 |
3 | import com.qiniu.android.storage.Recorder;
4 | import com.qiniu.android.utils.Cache;
5 |
6 | class ServerConfigCache {
7 |
8 | private static final String kServerConfigDiskKey = "ServerConfig";
9 | private static final String kServerUserConfigDiskKey = "ServerUserConfig";
10 |
11 | private final Cache configCache = new Cache.Builder(ServerConfig.class)
12 | .setVersion("v1")
13 | .builder();
14 | private final Cache userConfigCache = new Cache.Builder(ServerUserConfig.class)
15 | .setVersion("v1")
16 | .builder();
17 | ;
18 |
19 | ServerConfigCache() {
20 | }
21 |
22 | ServerConfig getConfig() {
23 | Cache.Object object = this.configCache.cacheForKey(kServerConfigDiskKey);
24 | if (object instanceof ServerConfig) {
25 | return (ServerConfig) object;
26 | }
27 | return null;
28 | }
29 |
30 | void setConfig(ServerConfig config) {
31 | this.configCache.cache(kServerConfigDiskKey, config, true);
32 | }
33 |
34 | ServerUserConfig getUserConfig() {
35 | Cache.Object object = this.userConfigCache.cacheForKey(kServerUserConfigDiskKey);
36 | if (object instanceof ServerUserConfig) {
37 | return (ServerUserConfig) object;
38 | }
39 | return null;
40 | }
41 |
42 | void setUserConfig(ServerUserConfig userConfig) {
43 | this.userConfigCache.cache(kServerUserConfigDiskKey, userConfig, true);
44 | }
45 |
46 | public synchronized void removeConfigCache() {
47 | this.configCache.clearDiskCache();
48 | this.configCache.clearMemoryCache();
49 | this.userConfigCache.clearDiskCache();
50 | this.userConfigCache.clearMemoryCache();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/storage/serverConfig/ServerUserConfig.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.storage.serverConfig;
2 |
3 | import com.qiniu.android.utils.Cache;
4 | import com.qiniu.android.utils.Utils;
5 |
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | /**
10 | * server user config
11 | *
12 | * @hidden
13 | */
14 | public class ServerUserConfig implements Cache.Object {
15 |
16 | private long timestamp;
17 | private long ttl = 10;
18 | private Boolean http3Enable;
19 | private Boolean networkCheckEnable;
20 |
21 | private JSONObject info;
22 |
23 | /**
24 | * 构造函数
25 | *
26 | * @param info json 数据
27 | */
28 | public ServerUserConfig(JSONObject info) {
29 | if (info == null) {
30 | return;
31 | }
32 |
33 | this.info = info;
34 |
35 | this.ttl = info.optLong("ttl", 5 * 60);
36 |
37 | if (info.opt("timestamp") != null) {
38 | this.timestamp = info.optLong("timestamp");
39 | }
40 | if (this.timestamp == 0) {
41 | this.timestamp = Utils.currentSecondTimestamp();
42 | try {
43 | info.putOpt("timestamp", this.timestamp);
44 | } catch (JSONException ignored) {
45 | }
46 | }
47 |
48 | JSONObject http3 = info.optJSONObject("http3");
49 | if (http3 != null && http3.opt("enabled") != null) {
50 | this.http3Enable = http3.optBoolean("enabled");
51 | }
52 |
53 | JSONObject networkCheck = info.optJSONObject("network_check");
54 | if (networkCheck != null && networkCheck.opt("enabled") != null) {
55 | this.networkCheckEnable = networkCheck.optBoolean("enabled");
56 | }
57 | }
58 |
59 | /**
60 | * 获取 json 数据
61 | *
62 | * @return json 数据
63 | */
64 | @Override
65 | public JSONObject toJson() {
66 | return info;
67 | }
68 |
69 | /**
70 | * HTTP/3 是否开启
71 | *
72 | * @return HTTP/3 是否开启
73 | */
74 | public Boolean getHttp3Enable() {
75 | return http3Enable;
76 | }
77 |
78 | /**
79 | * 网络检测是否开启
80 | *
81 | * @return 网络检测是否开启
82 | */
83 | public Boolean getNetworkCheckEnable() {
84 | return networkCheckEnable;
85 | }
86 |
87 | /**
88 | * 获取 json 信息
89 | *
90 | * @return json 信息
91 | */
92 | public JSONObject getInfo() {
93 | return toJson();
94 | }
95 |
96 | /**
97 | * 配置是否有效
98 | *
99 | * @return 配置是否有效
100 | */
101 | public boolean isValid() {
102 | return Utils.currentSecondTimestamp() < (this.timestamp + this.ttl);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/AsyncRun.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 |
6 | import java.util.Timer;
7 | import java.util.TimerTask;
8 | import java.util.concurrent.ExecutorService;
9 | import java.util.concurrent.Executors;
10 | import java.util.concurrent.LinkedBlockingQueue;
11 | import java.util.concurrent.ThreadPoolExecutor;
12 | import java.util.concurrent.TimeUnit;
13 |
14 |
15 | /**
16 | * Created by bailong on 14/10/22.
17 | *
18 | * @hidden
19 | */
20 | public final class AsyncRun {
21 |
22 | private static final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
23 |
24 | private static int threadPoolSize = 1;
25 | private static int maxThreadPoolSize = 6;
26 | private static ExecutorService executorService = new ThreadPoolExecutor(threadPoolSize, maxThreadPoolSize,
27 | 1000L, TimeUnit.MILLISECONDS,
28 | new LinkedBlockingQueue());
29 |
30 | private AsyncRun() {
31 | }
32 |
33 | /**
34 | * 主线程执行任务
35 | *
36 | * @param r 执行体
37 | */
38 | public static void runInMain(Runnable r) {
39 | if (Looper.getMainLooper() == Looper.myLooper()) {
40 | r.run();
41 | } else {
42 | mainThreadHandler.post(r);
43 | }
44 | }
45 |
46 | /**
47 | * 延迟执行任务
48 | *
49 | * @param delay 延迟执行时间,单位:ms
50 | * @param r 执行体
51 | */
52 | public static void runInMain(int delay, final Runnable r) {
53 |
54 | delayTimerTask(delay, new TimerTask() {
55 | @Override
56 | public void run() {
57 | mainThreadHandler.post(r);
58 | this.cancel();
59 | }
60 | });
61 | }
62 |
63 | /**
64 | * 后台执行任务
65 | *
66 | * @param r 执行体
67 | */
68 | public static void runInBack(Runnable r) {
69 | executorService.submit(r);
70 | }
71 |
72 | /**
73 | * 延迟执行任务
74 | *
75 | * @param delay 延迟执行时间,单位:ms
76 | * @param r 执行体
77 | */
78 | public static void runInBack(int delay, final Runnable r) {
79 |
80 | delayTimerTask(delay, new TimerTask() {
81 | @Override
82 | public void run() {
83 | executorService.submit(r);
84 | this.cancel();
85 | }
86 | });
87 | }
88 |
89 | private static void delayTimerTask(int delay, TimerTask timerTask) {
90 | Timer timer = new Timer();
91 | timer.schedule(timerTask, delay);
92 | }
93 |
94 | }
95 |
96 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/BytesUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * Bytes 工具
7 | *
8 | * @hidden
9 | */
10 | public class BytesUtils {
11 |
12 | private BytesUtils() {
13 | }
14 |
15 | /**
16 | * 获取 byte 数组的子数组
17 | *
18 | * @param source 源 byte 数组
19 | * @param from 子数组开始位置
20 | * @param length 子数组长度
21 | * @return 子数组
22 | * @throws IOException 异常
23 | */
24 | public static byte[] subBytes(byte[] source, int from, int length) throws IOException {
25 | if (length + from > source.length) {
26 | throw new IOException("copy bytes out of range");
27 | }
28 |
29 | byte[] buffer = new byte[length];
30 | System.arraycopy(source, from, buffer, 0, length);
31 | return buffer;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/Constants.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | /**
4 | * 常量定义
5 | */
6 | public class Constants {
7 |
8 | /**
9 | * Unknown network class
10 | */
11 | public static final String NETWORK_CLASS_UNKNOWN = "none";
12 |
13 | /**
14 | * wifi net work
15 | */
16 | public static final String NETWORK_WIFI = "wifi";
17 |
18 | /**
19 | * "2G" networks
20 | */
21 | public static final String NETWORK_CLASS_2_G = "2g";
22 |
23 | /**
24 | * "3G" networks
25 | */
26 | public static final String NETWORK_CLASS_3_G = "3g";
27 |
28 | /**
29 | * "4G" networks
30 | */
31 | public static final String NETWORK_CLASS_4_G = "4g";
32 |
33 | /**
34 | * "5G" networks
35 | */
36 | public static final String NETWORK_CLASS_5_G = "5g";
37 |
38 | private Constants() {
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/ContextGetter.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 |
6 | import com.qiniu.android.storage.GlobalConfiguration;
7 |
8 | /**
9 | * Created by bailong on 16/9/7.
10 | *
11 | * @hidden
12 | */
13 | public final class ContextGetter {
14 | private static Context context = applicationContext();
15 |
16 | private ContextGetter() {
17 | }
18 |
19 | /**
20 | * application Context
21 | *
22 | * @return Context
23 | */
24 | public static Context applicationContext() {
25 | if (context != null) {
26 | return context;
27 | }
28 |
29 | if (GlobalConfiguration.appContext != null) {
30 | return GlobalConfiguration.appContext;
31 | }
32 |
33 | Application app = getApplicationUsingReflection();
34 | if (app != null) {
35 | context = app.getApplicationContext();
36 | }
37 | return context;
38 | }
39 |
40 | private static Application getApplicationUsingReflection() {
41 | Application app = null;
42 | try {
43 | Class activity = Class.forName("android.app.ActivityThread");
44 | app = (Application) activity.getMethod("currentApplication").invoke(null, (Object[]) null);
45 |
46 | if (app == null) {
47 | Object localObject = activity.getMethod("currentActivityThread", new Class[0]).invoke(null, (Object[]) null);
48 | app = (Application) activity.getMethod("getApplication").invoke(localObject, (Object[]) null);
49 | }
50 | } catch (Exception e) {
51 | e.printStackTrace();
52 | }
53 |
54 | return app;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/Crc32.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.IOException;
6 | import java.util.zip.CRC32;
7 |
8 | /**
9 | * 计算文件或二进制数据的crc32校验码
10 | *
11 | * @hidden
12 | */
13 | public final class Crc32 {
14 |
15 | private Crc32() {
16 | }
17 |
18 | /**
19 | * 计算二进制字节校验码
20 | *
21 | * @param data 二进制数据
22 | * @param offset 起始字节索引
23 | * @param length 校验字节长度
24 | * @return 校验码
25 | */
26 | public static long bytes(byte[] data, int offset, int length) {
27 | CRC32 crc32 = new CRC32();
28 | crc32.update(data, offset, length);
29 | return crc32.getValue();
30 | }
31 |
32 | /**
33 | * 计算二进制字节校验码
34 | *
35 | * @param data 二进制数据
36 | * @return 校验码
37 | */
38 | public static long bytes(byte[] data) {
39 | return bytes(data, 0, data.length);
40 | }
41 |
42 | /**
43 | * 对文件内容计算crc32校验码
44 | *
45 | * @param f 需要计算crc32校验码的文件
46 | * @return crc校验码
47 | * @throws IOException 读取文件异常
48 | */
49 | public static long file(File f) throws IOException {
50 | FileInputStream fi = new FileInputStream(f);
51 | byte[] buff = new byte[64 * 1024];
52 | int len;
53 | CRC32 crc32 = new CRC32();
54 | try {
55 | while ((len = fi.read(buff)) != -1) {
56 | crc32.update(buff, 0, len);
57 | }
58 | } catch (Exception e) {
59 | e.printStackTrace();
60 | } finally {
61 | fi.close();
62 | }
63 |
64 | return crc32.getValue();
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/GZipUtil.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.IOException;
6 | import java.util.zip.GZIPInputStream;
7 | import java.util.zip.GZIPOutputStream;
8 |
9 | /**
10 | * GZip 工具
11 | *
12 | * @hidden
13 | */
14 | public class GZipUtil {
15 |
16 | private GZipUtil() {
17 | }
18 |
19 | /**
20 | * 压缩字符串
21 | *
22 | * @param string 带压缩数据
23 | * @return 压缩后的数据
24 | */
25 | public static byte[] gZip(String string) {
26 | if (string == null) {
27 | return null;
28 | }
29 | return gZip(string.getBytes());
30 | }
31 |
32 | /**
33 | * 压缩 byte 数组
34 | *
35 | * @param bytes 带压缩数据
36 | * @return 压缩后的数据
37 | */
38 | public static byte[] gZip(byte[] bytes) {
39 | if (bytes == null) {
40 | return null;
41 | }
42 | if (bytes.length == 0) {
43 | return bytes;
44 | }
45 |
46 | ByteArrayOutputStream out = new ByteArrayOutputStream();
47 | GZIPOutputStream gzip = null;
48 | try {
49 | gzip = new GZIPOutputStream(out);
50 | gzip.write(bytes);
51 | } catch (IOException e) {
52 | } finally {
53 | if (gzip != null) {
54 | try {
55 | gzip.close();
56 | } catch (IOException e) {
57 | }
58 | }
59 | }
60 |
61 | return out.toByteArray();
62 | }
63 |
64 | /**
65 | * 解压缩 byte 数组
66 | *
67 | * @param bytes 待解压缩数据
68 | * @return 解压缩后的数据
69 | */
70 | public static byte[] gUnzip(byte[] bytes) {
71 | if (bytes == null) {
72 | return null;
73 | }
74 | if (bytes.length == 0) {
75 | return bytes;
76 | }
77 |
78 | ByteArrayOutputStream out = new ByteArrayOutputStream();
79 | ByteArrayInputStream in = new ByteArrayInputStream(bytes);
80 |
81 | GZIPInputStream gunzip = null;
82 | try {
83 | gunzip = new GZIPInputStream(in);
84 | byte[] buffer = new byte[256];
85 | int n;
86 | while ((n = gunzip.read(buffer)) >= 0) {
87 | out.write(buffer, 0, n);
88 | }
89 | } catch (IOException e) {
90 | } finally {
91 | if (gunzip != null) {
92 | try {
93 | gunzip.close();
94 | } catch (IOException e) {
95 | }
96 | }
97 | }
98 |
99 | return out.toByteArray();
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/Json.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONObject;
5 |
6 | import java.util.Collection;
7 | import java.util.Map;
8 |
9 | /**
10 | * Created by long on 2017/7/25.
11 | *
12 | * @hidden
13 | */
14 | public final class Json {
15 |
16 | private Json() {
17 | }
18 |
19 | /**
20 | * map 转 json
21 | *
22 | * @param map map
23 | * @return json string
24 | */
25 | public static String encodeMap(Map map) {
26 | JSONObject obj = new JSONObject(map);
27 | return obj.toString();
28 | }
29 |
30 | /**
31 | * Collection 转 json
32 | *
33 | * @param collection Collection
34 | * @return json string
35 | */
36 | public static String encodeList(Collection collection) {
37 | JSONArray array = new JSONArray(collection);
38 | return array.toString();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/ListUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * List 工具类
7 | */
8 | public class ListUtils {
9 |
10 | /**
11 | * 判断 List 是否为空
12 | *
13 | * @param objects List
14 | * @return 是否为空
15 | * @param List 中的元素类型
16 | */
17 | public static boolean isEmpty(List objects) {
18 | return objects == null || objects.isEmpty();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/ListVector.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collection;
5 | import java.util.List;
6 | import java.util.Vector;
7 | import java.util.concurrent.CopyOnWriteArrayList;
8 |
9 | /**
10 | * ListVector
11 | *
12 | * @param 元素类型
13 | * @hidden
14 | */
15 | public class ListVector extends Vector {
16 |
17 | /**
18 | * 构造函数
19 | */
20 | public ListVector() {
21 | super();
22 | }
23 |
24 | /**
25 | * 构造函数
26 | *
27 | * @param initialCapacity initialCapacity
28 | * @param capacityIncrement capacityIncrement
29 | */
30 | public ListVector(int initialCapacity, int capacityIncrement) {
31 | super(initialCapacity, capacityIncrement);
32 | }
33 |
34 | /**
35 | * 对象遍历
36 | *
37 | * @param handler handler
38 | */
39 | public synchronized void enumerateObjects(EnumeratorHandler super E> handler) {
40 | if (handler == null) {
41 | return;
42 | }
43 |
44 | final E[] elementData = (E[]) this.elementData;
45 | final int elementCount = this.elementCount;
46 | for (int i = 0; i < elementCount; i++) {
47 | if (handler.enumerate(elementData[i])) {
48 | break;
49 | }
50 | }
51 | }
52 |
53 | /**
54 | * create subList
55 | *
56 | * @param fromIndex low endpoint (inclusive) of the subList
57 | * @param toIndex high endpoint (exclusive) of the subList
58 | * @return subList
59 | */
60 | @Override
61 | public synchronized ListVector subList(int fromIndex, int toIndex) {
62 | ListVector listVector = new ListVector();
63 | // c.toArray might (incorrectly) not return Object[] (see 6260652)
64 | if (elementData.getClass() != Object[].class) {
65 | listVector.elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
66 | listVector.elementCount = listVector.elementData.length;
67 | } else {
68 | listVector.elementData = Arrays.copyOf(elementData, elementCount);
69 | listVector.elementCount = elementCount;
70 | }
71 | return listVector;
72 | }
73 |
74 | /**
75 | * EnumeratorHandler
76 | *
77 | * @param enumerate 对象的类型
78 | * @hidden
79 | */
80 | public interface EnumeratorHandler {
81 |
82 | /**
83 | * enumerate
84 | *
85 | * @param t T
86 | * @return stop
87 | */
88 | boolean enumerate(T t);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/MD5.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.security.MessageDigest;
4 |
5 | import com.qiniu.android.dns.util.Hex;
6 |
7 | /**
8 | * MD5 util
9 | *
10 | * @hidden
11 | */
12 | public class MD5 {
13 |
14 | private MD5() {
15 | }
16 |
17 | /**
18 | * MD5 加密
19 | *
20 | * @param data 带加密数据
21 | * @return 已加密数据
22 | */
23 | public static String encrypt(byte[] data) {
24 | try {
25 | MessageDigest digest = MessageDigest.getInstance("MD5");
26 | digest.update(data);
27 | return Hex.encodeHexString(digest.digest());
28 | } catch (Exception e) {
29 | e.printStackTrace();
30 | }
31 | return null;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/MapUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.util.Map;
4 |
5 | /**
6 | * Map 工具类
7 | */
8 | public class MapUtils {
9 |
10 | /**
11 | * 判断 Map 是否为空
12 | *
13 | * @param objects Map
14 | * @return 是否为空
15 | * @param key 类型
16 | * @param value 类型
17 | */
18 | public static boolean isEmpty(Map objects) {
19 | return objects == null || objects.isEmpty();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/UrlSafeBase64.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import android.util.Base64;
4 |
5 | import com.qiniu.android.common.Constants;
6 |
7 | import java.io.UnsupportedEncodingException;
8 |
9 | /**
10 | * URL安全的Base64编码和解码
11 | *
12 | * @hidden
13 | */
14 | public final class UrlSafeBase64 {
15 |
16 | private UrlSafeBase64() {
17 | }
18 |
19 | /**
20 | * 编码字符串
21 | *
22 | * @param data 待编码字符串
23 | * @return 结果字符串
24 | */
25 | public static String encodeToString(String data) {
26 | try {
27 | return encodeToString(data.getBytes(Constants.UTF_8));
28 | } catch (UnsupportedEncodingException e) {
29 | //never in
30 | e.printStackTrace();
31 | }
32 | return null;
33 | }
34 |
35 | /**
36 | * 编码数据
37 | *
38 | * @param data 字节数组
39 | * @return 结果字符串
40 | */
41 | public static String encodeToString(byte[] data) {
42 | return Base64.encodeToString(data, Base64.URL_SAFE | Base64.NO_WRAP);
43 | }
44 |
45 | /**
46 | * 解码数据
47 | *
48 | * @param data 编码过的字符串
49 | * @return 原始数据
50 | */
51 | public static byte[] decode(String data) {
52 | try {
53 | return Base64.decode(data, Base64.URL_SAFE | Base64.NO_WRAP);
54 | } catch (RuntimeException e) {
55 | return null;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/UrlUtils.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | /**
4 | * UrlUtils
5 | *
6 | * @hidden
7 | */
8 | public class UrlUtils {
9 |
10 | private UrlUtils() {
11 | }
12 |
13 | /**
14 | * 移除 host 中的 scheme
15 | *
16 | * @param host host
17 | * @return host
18 | */
19 | public static String removeHostScheme(String host) {
20 | if (host == null || StringUtils.isNullOrEmpty(host)) {
21 | return null;
22 | }
23 |
24 | host = host.replace("http://", "");
25 | host = host.replace("https://", "");
26 | return host;
27 | }
28 |
29 |
30 | /**
31 | * 如果 host 包含 scheme 则优先使用 host 中包含的 scheme
32 | * 如果 host 不包含 scheme 则按照 useHttps 增加 scheme
33 | *
34 | * @param host host
35 | * @param useHttps 是否使用 https 请求
36 | * @return url
37 | */
38 | public static String setHostScheme(String host, boolean useHttps) {
39 | if (StringUtils.isNullOrEmpty(host)) {
40 | return null;
41 | }
42 |
43 | if (host.startsWith("http://") || host.startsWith("https://")) {
44 | return host;
45 | }
46 |
47 | return (useHttps ? "https://" : "http://") + host;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/library/src/main/java/com/qiniu/android/utils/Wait.java:
--------------------------------------------------------------------------------
1 | package com.qiniu.android.utils;
2 |
3 | import java.util.concurrent.CountDownLatch;
4 |
5 | /**
6 | * wait
7 | *
8 | * @hidden
9 | */
10 | public class Wait {
11 |
12 | final CountDownLatch completeSingle = new CountDownLatch(1);
13 |
14 | /**
15 | * 构造函数
16 | */
17 | public Wait() {
18 | }
19 |
20 | /**
21 | * 开始等待
22 | */
23 | public void startWait() {
24 | while (completeSingle.getCount() > 0) {
25 | try {
26 | completeSingle.await();
27 | break;
28 | } catch (InterruptedException e) {
29 | }
30 | }
31 | }
32 |
33 | /**
34 | * 停止等待
35 | */
36 | public void stopWait() {
37 | completeSingle.countDown();
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | qiniu-sdk
3 |
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "android-sdk"
2 | include ':library'
3 |
--------------------------------------------------------------------------------