@@ -55,65 +55,93 @@ class DefaultHostProvider extends HostFreezer {
5555
5656 final _http = Dio ();
5757 // 缓存的上传区域
58- final _stashedUpDomains = < _Domain > [];
58+ final _stashedUpHosts = < _Host > [];
5959 // accessKey:bucket 用此 key 判断是否 up host 需要走缓存
6060 String ? _cacheKey;
6161
62- @override
63- Future <String > getUpHost ({
62+ Future <List <_Host >> getUpHostsFromV4Query ({
6463 required String accessKey,
6564 required String bucket,
6665 bool accelerateUploading = false ,
67- bool transregional = false ,
68- int regionIndex = 0 ,
6966 }) async {
70- _unfreezeUpDomains ();
71- final upDomains = < _Domain > [];
72- final cacheKey =
73- '$accessKey :$bucket :${accelerateUploading ? '1' : '0' }:${_getHostsMD5 (bucketHosts )}' ;
74- if (cacheKey == _cacheKey && _stashedUpDomains.isNotEmpty) {
75- upDomains.addAll (_stashedUpDomains);
67+ final upHosts = < _Host > [];
68+ final cacheKey = '$accessKey :'
69+ '$bucket :'
70+ '${accelerateUploading ? '1' : '0' }:'
71+ '${_getHostsMD5 (bucketHosts )}' ;
72+ if (cacheKey == _cacheKey && _stashedUpHosts.isNotEmpty) {
73+ upHosts.addAll (_stashedUpHosts);
7674 } else {
7775 final data = await _getUrl (
7876 bucketHosts,
7977 'v4/query?ak=$accessKey &bucket=$bucket ' ,
8078 protocol,
8179 _http,
8280 );
83- Iterable < _Host > hosts = data['hosts' ]
81+ final hosts = data['hosts' ]
8482 .map ((dynamic json) => _Host .fromJson (json as Map ))
8583 .cast <_Host >();
84+ if (hosts.isEmpty) _throwNoAvailableRegionError ();
8685
87- if (! transregional) {
88- final host = hosts.elementAtOrNull (regionIndex);
89- if (host == null ) {
90- _throwNoAvailableRegionError ();
91- }
92- hosts = [host];
93- }
86+ _cacheKey = cacheKey;
87+ _stashedUpHosts.addAll (hosts);
88+ }
89+ return upHosts;
90+ }
91+
92+ @override
93+ Future <String > getUpHost ({
94+ required String accessKey,
95+ required String bucket,
96+ bool accelerateUploading = false ,
97+ // 表单上传这个值为true,则始终在所有可用区域之间选择一个可用域名
98+ // 分片上传为false,则始终选择 regionIndex 指定的区域
99+ bool transregional = false ,
100+ int regionIndex = 0 ,
101+ }) async {
102+ _unfreezeUpDomains ();
103+
104+ final upHosts = await getUpHostsFromV4Query (
105+ accessKey: accessKey,
106+ bucket: bucket,
107+ accelerateUploading: accelerateUploading,
108+ );
94109
95- for (final host in hosts) {
110+ if (transregional) {
111+ // 表单上传
112+ final upDomains = < _Domain > {};
113+ // 全都不可用了,随机选择一个域名返回
114+ for (final host in upHosts) {
96115 final domainList = host.up['domains' ].cast <String >() as List <String >;
97116 final domains = domainList.map ((domain) => _Domain (domain));
98117 upDomains.addAll (domains);
99118 }
100119
101- _cacheKey = cacheKey;
102- _stashedUpDomains.addAll (upDomains);
103- }
104-
105- // 每次都从头遍历一遍,最合适的 host 总是会排在最前面
106- for (var index = 0 ; index < upDomains.length; index++ ) {
107- final availableDomain = upDomains.elementAt (index);
108- // 检查看起来可用的 host 是否之前被冻结过
109- final frozen = isFrozen ('$protocol ://${availableDomain .value }' );
120+ // 每次都从头遍历一遍,最合适的 host 总是会排在最前面
121+ for (var index = 0 ; index < upDomains.length; index++ ) {
122+ final availableDomain = upDomains.elementAt (index);
123+ // 检查看起来可用的 host 是否之前被冻结过
124+ final frozen = isFrozen ('$protocol ://${availableDomain .value }' );
110125
111- if (! frozen) {
112- return '$protocol ://${availableDomain .value }' ;
126+ if (! frozen) {
127+ return '$protocol ://${availableDomain .value }' ;
128+ }
129+ }
130+ return '$protocol ://${upDomains .toList ().mustGetRandomElement ()}' ;
131+ } else {
132+ // 分片上传
133+ if (regionIndex < upHosts.length) {
134+ // 分片上传不能随机选择一个域名返回,需要上层切换regionIndex
135+ _throwNoAvailableHostError ();
136+ } else {
137+ // 已经至少把所有的可用region都尝试过了,直接继续轮转回开头的region
138+ final host = upHosts.elementAt (regionIndex % upHosts.length);
139+ // 在这个region里面随机选择一个域名返回
140+ final domainList = host.up['domains' ].cast <String >() as List <String >;
141+ final domains = domainList.map ((domain) => _Domain (domain));
142+ return '$protocol ://${domains .toList ().mustGetRandomElement ()}' ;
113143 }
114144 }
115- // 全都不可用了,随机选择一个域名返回
116- return '$protocol ://${upDomains .mustGetRandomElement ()}' ;
117145 }
118146}
119147
@@ -170,6 +198,8 @@ class DefaultHostProviderV2 extends HostFreezer {
170198 required String accessKey,
171199 required String bucket,
172200 bool accelerateUploading = false ,
201+ // 表单上传这个值为true,则始终在所有可用区域之间选择一个可用域名
202+ // 分片上传为false,则始终选择 regionIndex 指定的区域
173203 bool transregional = false ,
174204 int regionIndex = 0 ,
175205 }) async {
@@ -181,35 +211,58 @@ class DefaultHostProviderV2 extends HostFreezer {
181211 bucketName: bucket,
182212 accelerateUploading: accelerateUploading,
183213 );
184- final regions = < Region > [];
214+
185215 if (transregional) {
186- regions.addAll (regionsProvider.regions);
187- } else {
188- final region = regionsProvider.regions.elementAtOrNull (regionIndex);
189- if (region == null ) {
190- _throwNoAvailableRegionError ();
216+ // 表单上传
217+ final regions = regionsProvider.regions;
218+ if (regions.isEmpty) _throwNoAvailableRegionError ();
219+
220+ for (final region in regions) {
221+ final unfrozenDomain = region.up
222+ .map ((domain) => _makeHost (domain, useHttps: _useHttps))
223+ .firstWhere (
224+ (domain) => ! isFrozen (domain),
225+ orElse: () => '' ,
226+ );
227+ if (unfrozenDomain != '' ) {
228+ return unfrozenDomain;
229+ }
191230 }
192- regions. add (region);
193- }
194- for ( final region in regions) {
195- final unfrozenDomain = region .up
231+ // 全都不可用了,随机选择一个域名返回
232+ return regions
233+ . mustGetRandomElement ()
234+ .up
196235 .map ((domain) => _makeHost (domain, useHttps: _useHttps))
197- .firstWhere (
198- (domain) => ! isFrozen (domain),
199- orElse: () => '' ,
200- );
201- if (unfrozenDomain != '' ) {
202- return unfrozenDomain;
236+ .toList ()
237+ .mustGetRandomElement ();
238+ } else {
239+ // 分片上传
240+ if (regionIndex < regionsProvider.regions.length) {
241+ final unfrozenDomain = regionsProvider.regions
242+ .elementAt (regionIndex)
243+ .up
244+ .map ((domain) => _makeHost (domain, useHttps: _useHttps))
245+ .firstWhere (
246+ (domain) => ! isFrozen (domain),
247+ orElse: () => '' ,
248+ );
249+ if (unfrozenDomain != '' ) {
250+ return unfrozenDomain;
251+ }
252+ // 分片上传不能随机选择一个域名返回,需要上层切换regionIndex
253+ _throwNoAvailableHostError ();
254+ } else {
255+ // 已经至少把所有的可用region都尝试过了,直接继续轮转回开头的region
256+ final index = regionIndex % regionsProvider.regions.length;
257+ // 这里面的域名很可能都是仍然处于冻结状态的,这里随机选择一个返回
258+ return regionsProvider.regions
259+ .elementAt (index)
260+ .up
261+ .map ((domain) => _makeHost (domain, useHttps: _useHttps))
262+ .toList ()
263+ .mustGetRandomElement ();
203264 }
204265 }
205-
206- // 全都不可用了,随机选择一个域名返回
207- return regions
208- .mustGetRandomElement ()
209- .up
210- .map ((domain) => _makeHost (domain, useHttps: _useHttps))
211- .toList ()
212- .mustGetRandomElement ();
213266 }
214267
215268 Future <BucketRegionsQuery > get query => _getQuery ();
@@ -284,6 +337,13 @@ void _checkResponse(Response response) {
284337 }
285338}
286339
340+ Never _throwNoAvailableHostError () {
341+ throw StorageError (
342+ type: StorageErrorType .NO_AVAILABLE_HOST ,
343+ message: '没有可用的上传域名' ,
344+ );
345+ }
346+
287347Never _throwNoAvailableRegionError () {
288348 throw StorageError (
289349 type: StorageErrorType .NO_AVAILABLE_REGION ,
0 commit comments