|
1 | 1 | const os = require('os');
|
2 | 2 | const pkg = require('../package.json');
|
| 3 | +const { Endpoint } = require('./httpc/endpoint'); |
| 4 | +const { Region } = require('./httpc/region'); |
| 5 | +const { StaticEndpointsProvider } = require('./httpc/endpointsProvider'); |
| 6 | +const crypto = require('crypto'); |
| 7 | +const { |
| 8 | + CachedRegionsProvider, |
| 9 | + QueryRegionsProvider |
| 10 | +} = require('./httpc/regionsProvider'); |
3 | 11 |
|
4 | 12 | exports.ACCESS_KEY = '<PLEASE APPLY YOUR ACCESS KEY>';
|
5 | 13 | exports.SECRET_KEY = '<DONT SEND YOUR SECRET KEY TO ANYONE>';
|
6 | 14 |
|
7 |
| -var defaultUserAgent = function () { |
| 15 | +const defaultUserAgent = function () { |
8 | 16 | return 'QiniuNodejs/' + pkg.version + ' (' + os.type() + '; ' + os.platform() +
|
9 | 17 | '; ' + os.arch() + '; )';
|
10 | 18 | };
|
@@ -50,68 +58,180 @@ Object.defineProperty(exports, 'UC_HOST', {
|
50 | 58 | exports.RPC_HTTP_AGENT = null;
|
51 | 59 | exports.RPC_HTTPS_AGENT = null;
|
52 | 60 |
|
53 |
| -exports.Config = function Config (options) { |
| 61 | +/** |
| 62 | + * @class |
| 63 | + * @constructor |
| 64 | + * @param {Object} [options] |
| 65 | + * @param {boolean} [options.useHttpsDomain] |
| 66 | + * @param {boolean} [options.useCdnDomain] |
| 67 | + * @param {EndpointsProvider} [options.ucEndpointsProvider] |
| 68 | + * @param {EndpointsProvider} [options.queryRegionsEndpointsProvider] |
| 69 | + * @param {RegionsProvider} [options.regionsProvider] |
| 70 | + * @param {Zone} [options.zone] |
| 71 | + * @param {number} [options.zoneExpire] |
| 72 | + */ |
| 73 | +function Config (options) { |
54 | 74 | options = options || {};
|
55 | 75 | // use http or https protocol
|
56 | 76 | this.useHttpsDomain = !!(options.useHttpsDomain || false);
|
57 |
| - // use cdn accerlated domains, this is not work with auto query region |
| 77 | + // use cdn accelerated domains, this is not work with auto query region |
58 | 78 | this.useCdnDomain = !!(options.useCdnDomain && true);
|
| 79 | + // custom uc endpoints |
| 80 | + this.ucEndpointsProvider = options.ucEndpointsProvider || null; |
| 81 | + // custom query region endpoints |
| 82 | + this.queryRegionsEndpointsProvider = options.queryRegionsEndpointsProvider || null; |
| 83 | + // custom regions |
| 84 | + this.regionsProvider = options.regionsProvider || null; |
| 85 | + |
| 86 | + // deprecated |
59 | 87 | // zone of the bucket
|
60 |
| - // z0 huadong, z1 huabei, z2 huanan, na0 beimei |
61 | 88 | this.zone = options.zone || null;
|
62 | 89 | this.zoneExpire = options.zoneExpire || -1;
|
63 |
| - // only available with upload for now |
64 |
| - this.regionsProvider = options.regionsProvider || null; |
| 90 | +} |
| 91 | + |
| 92 | +/** |
| 93 | + * @returns {EndpointsProvider} |
| 94 | + */ |
| 95 | +Config.prototype.getUcEndpointsProvider = function () { |
| 96 | + if (this.ucEndpointsProvider) { |
| 97 | + return this.ucEndpointsProvider; |
| 98 | + } |
| 99 | + |
| 100 | + return new Endpoint( |
| 101 | + UC_HOST, |
| 102 | + { |
| 103 | + defaultScheme: this.useHttpsDomain ? 'https' : 'http' |
| 104 | + } |
| 105 | + ); |
65 | 106 | };
|
66 | 107 |
|
67 |
| -exports.Zone = function ( |
68 |
| - srcUpHosts, |
69 |
| - cdnUpHosts, |
70 |
| - ioHost, |
71 |
| - rsHost, |
72 |
| - rsfHost, |
73 |
| - apiHost |
74 |
| -) { |
75 |
| - this.srcUpHosts = srcUpHosts || []; |
76 |
| - this.cdnUpHosts = cdnUpHosts || []; |
77 |
| - this.ioHost = ioHost || ''; |
78 |
| - this.rsHost = rsHost; |
79 |
| - this.rsfHost = rsfHost; |
80 |
| - this.apiHost = apiHost; |
81 |
| - |
82 |
| - // set specific hosts if possible |
83 |
| - const dotIndex = this.ioHost.indexOf('.'); |
84 |
| - if (dotIndex !== -1) { |
85 |
| - const ioTag = this.ioHost.substring(0, dotIndex); |
86 |
| - const zoneSepIndex = ioTag.indexOf('-'); |
87 |
| - if (zoneSepIndex !== -1) { |
88 |
| - const zoneTag = ioTag.substring(zoneSepIndex + 1); |
89 |
| - switch (zoneTag) { |
90 |
| - case 'z1': |
91 |
| - !this.rsHost && (this.rsHost = 'rs-z1.qbox.me'); |
92 |
| - !this.rsfHost && (this.rsfHost = 'rsf-z1.qbox.me'); |
93 |
| - !this.apiHost && (this.apiHost = 'api-z1.qiniuapi.com'); |
94 |
| - break; |
95 |
| - case 'z2': |
96 |
| - !this.rsHost && (this.rsHost = 'rs-z2.qbox.me'); |
97 |
| - !this.rsfHost && (this.rsfHost = 'rsf-z2.qbox.me'); |
98 |
| - !this.apiHost && (this.apiHost = 'api-z2.qiniuapi.com'); |
99 |
| - break; |
100 |
| - case 'na0': |
101 |
| - !this.rsHost && (this.rsHost = 'rs-na0.qbox.me'); |
102 |
| - !this.rsfHost && (this.rsfHost = 'rsf-na0.qbox.me'); |
103 |
| - !this.apiHost && (this.apiHost = 'api-na0.qiniuapi.com'); |
104 |
| - break; |
105 |
| - case 'as0': |
106 |
| - !this.rsHost && (this.rsHost = 'rs-as0.qbox.me'); |
107 |
| - !this.rsfHost && (this.rsfHost = 'rsf-as0.qbox.me'); |
108 |
| - !this.apiHost && (this.apiHost = 'api-as0.qiniuapi.com'); |
109 |
| - break; |
| 108 | +/** |
| 109 | + * @private |
| 110 | + * @returns {EndpointsProvider} |
| 111 | + */ |
| 112 | +Config.prototype._getQueryRegionEndpointsProvider = function () { |
| 113 | + if (this.queryRegionsEndpointsProvider) { |
| 114 | + return this.queryRegionsEndpointsProvider; |
| 115 | + } |
| 116 | + |
| 117 | + if (this.ucEndpointsProvider) { |
| 118 | + return this.ucEndpointsProvider; |
| 119 | + } |
| 120 | + |
| 121 | + const queryRegionsHosts = [QUERY_REGION_HOST].concat(QUERY_REGION_BACKUP_HOSTS); |
| 122 | + return new StaticEndpointsProvider(queryRegionsHosts.map(h => |
| 123 | + new Endpoint( |
| 124 | + h, |
| 125 | + { |
| 126 | + defaultScheme: this.useHttpsDomain ? 'https' : 'http' |
110 | 127 | }
|
111 |
| - } |
| 128 | + ) |
| 129 | + )); |
| 130 | +}; |
| 131 | + |
| 132 | +/** |
| 133 | + * @param {Object} [options] |
| 134 | + * @param {string} [options.bucketName] |
| 135 | + * @param {string} [options.accessKey] |
| 136 | + * @returns {Promise<RegionsProvider>} |
| 137 | + */ |
| 138 | +Config.prototype.getRegionsProvider = function (options) { |
| 139 | + // returns custom regions provider, if it's configured |
| 140 | + if (this.regionsProvider) { |
| 141 | + return Promise.resolve(this.regionsProvider); |
| 142 | + } |
| 143 | + |
| 144 | + // backward compatibility with custom zone configuration |
| 145 | + const zoneProvider = this._getRegionsProviderFromZone(); |
| 146 | + if (zoneProvider) { |
| 147 | + return Promise.resolve(zoneProvider); |
| 148 | + } |
| 149 | + |
| 150 | + // get default regions provider |
| 151 | + const { |
| 152 | + bucketName, |
| 153 | + accessKey |
| 154 | + } = options || {}; |
| 155 | + if (!bucketName || !accessKey) { |
| 156 | + return Promise.reject( |
| 157 | + new Error('bucketName and accessKey is required for query regions') |
| 158 | + ); |
| 159 | + } |
| 160 | + return this._getDefaultRegionsProvider({ |
| 161 | + bucketName, |
| 162 | + accessKey |
| 163 | + }); |
| 164 | +}; |
| 165 | + |
| 166 | +/** |
| 167 | + * @private |
| 168 | + * @returns {RegionsProvider | undefined} |
| 169 | + */ |
| 170 | +Config.prototype._getRegionsProviderFromZone = function () { |
| 171 | + let zoneTTL; |
| 172 | + let shouldUseZone; |
| 173 | + if (this.zoneExpire > 0) { |
| 174 | + zoneTTL = this.zoneExpire - Math.trunc(Date.now() / 1000); |
| 175 | + shouldUseZone = this.zone && zoneTTL > 0; |
| 176 | + } else { |
| 177 | + zoneTTL = -1; |
| 178 | + shouldUseZone = Boolean(this.zone); |
| 179 | + } |
| 180 | + if (!shouldUseZone) { |
| 181 | + return; |
112 | 182 | }
|
| 183 | + return Region.fromZone(this.zone, { |
| 184 | + ttl: zoneTTL, |
| 185 | + isPreferCdnHost: this.useCdnDomain, |
| 186 | + preferredScheme: this.useHttpsDomain ? 'https' : 'http' |
| 187 | + }); |
| 188 | +}; |
| 189 | + |
| 190 | +/** |
| 191 | + * @private |
| 192 | + * @param {Object} options |
| 193 | + * @param {string} options.bucketName |
| 194 | + * @param {string} options.accessKey |
| 195 | + * @returns {Promise<RegionsProvider>} |
| 196 | + */ |
| 197 | +Config.prototype._getDefaultRegionsProvider = function (options) { |
| 198 | + const { |
| 199 | + bucketName, |
| 200 | + accessKey |
| 201 | + } = options; |
113 | 202 |
|
114 |
| - !this.rsHost && (this.rsHost = 'rs.qiniu.com'); |
115 |
| - !this.rsfHost && (this.rsfHost = 'rsf.qiniu.com'); |
116 |
| - !this.apiHost && (this.apiHost = 'api.qiniuapi.com'); |
| 203 | + const queryRegionsEndpointsProvider = this._getQueryRegionEndpointsProvider(); |
| 204 | + return queryRegionsEndpointsProvider |
| 205 | + .getEndpoints() |
| 206 | + .then(endpoints => { |
| 207 | + const endpointsMd5 = endpoints |
| 208 | + .map(e => e.host) |
| 209 | + .sort() |
| 210 | + .reduce( |
| 211 | + (hash, host) => hash.update(host), |
| 212 | + crypto.createHash('md5') |
| 213 | + ) |
| 214 | + .digest('hex'); |
| 215 | + const cacheKey = [ |
| 216 | + endpointsMd5, |
| 217 | + accessKey, |
| 218 | + bucketName |
| 219 | + ].join(':'); |
| 220 | + return new CachedRegionsProvider({ |
| 221 | + cacheKey, |
| 222 | + baseRegionsProvider: new QueryRegionsProvider({ |
| 223 | + accessKey: accessKey, |
| 224 | + bucketName: bucketName, |
| 225 | + endpointsProvider: queryRegionsEndpointsProvider, |
| 226 | + preferredScheme: this.useHttpsDomain ? 'https' : 'http' |
| 227 | + }) |
| 228 | + }); |
| 229 | + }); |
117 | 230 | };
|
| 231 | + |
| 232 | +exports.Config = Config; |
| 233 | +/** |
| 234 | + * backward compatibility |
| 235 | + * @deprecated use qiniu/httpc/region.js instead |
| 236 | + */ |
| 237 | +exports.Zone = require('./zone').Zone; |
0 commit comments