Skip to content

Commit 47037d0

Browse files
author
carsonxu
committed
update uploadId cache
1 parent 14a2769 commit 47037d0

8 files changed

+475
-429
lines changed

dist/cos-js-sdk-v5.js

+250-225
Large diffs are not rendered by default.

dist/cos-js-sdk-v5.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"description": "JavaScript SDK for [腾讯云对象存储](https://cloud.tencent.com/product/cos)",
55
"main": "index.js",
66
"scripts": {
7-
"dev": "cross-env NODE_ENV=development webpack -w",
87
"server": "node server/sts.js",
8+
"dev": "cross-env NODE_ENV=development webpack -w",
99
"build": "cross-env NODE_ENV=production webpack",
1010
"cos-auth.min.js": "uglifyjs ./demo/common/cos-auth.js -o ./demo/common/cos-auth.min.js -c -m"
1111
},

src/advance.js

+60-130
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
var session = require('./session');
12
var Async = require('./async');
23
var EventProxy = require('./event').EventProxy;
34
var util = require('./util');
@@ -41,13 +42,13 @@ function sliceUploadFile(params, callback) {
4142
SliceList: UploadData.SliceList,
4243
}, function (err, data) {
4344
if (!self._isRunningTask(TaskId)) return;
44-
delete uploadIdUsing[UploadData.UploadId];
45+
session.removeUsing(UploadData.UploadId);
4546
if (err) {
4647
onProgress(null, true);
4748
return ep.emit('error', err);
4849
}
50+
session.removeUploadId(UploadData.UploadId);
4951
onProgress({loaded: FileSize, total: FileSize}, true);
50-
removeUploadId.call(self, UploadData.UploadId);
5152
ep.emit('upload_complete', data);
5253
});
5354
});
@@ -56,14 +57,9 @@ function sliceUploadFile(params, callback) {
5657
ep.on('get_upload_data_finish', function (UploadData) {
5758

5859
// 处理 UploadId 缓存
59-
var uuid = util.getFileUUID(Body, params.ChunkSize);
60-
uuid && setUploadId.call(self, uuid, UploadData.UploadId); // 缓存 UploadId
61-
uploadIdUsing[UploadData.UploadId] = true; // 标记 UploadId 为正在使用
62-
TaskId && self.on('inner-kill-task', function (data) {
63-
if (data.TaskId === TaskId && data.toState === 'canceled') {
64-
delete uploadIdUsing[UploadData.UploadId]; // 去除 UploadId 正在使用的标记
65-
}
66-
});
60+
var uuid = session.getFileId(Body, params.ChunkSize, Bucket, Key);
61+
uuid && session.saveUploadId(uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId
62+
session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用
6763

6864
// 获取 UploadId
6965
onProgress(null, true); // 任务状态开始 uploading
@@ -157,75 +153,6 @@ function sliceUploadFile(params, callback) {
157153

158154
}
159155

160-
161-
// 按照文件特征值,缓存 UploadId
162-
var uploadIdCache;
163-
var uploadIdUsing = {};
164-
var uploadIdCacheKey = 'cos_sdk_upload_cache';
165-
function initUploadId() {
166-
var cacheLimit = this.options.UploadIdCacheLimit;
167-
if (!uploadIdCache) {
168-
if (cacheLimit) {
169-
try {
170-
uploadIdCache = JSON.parse(localStorage.getItem(uploadIdCacheKey)) || [];
171-
} catch (e) {}
172-
}
173-
if (!uploadIdCache) {
174-
uploadIdCache = [];
175-
}
176-
}
177-
}
178-
function setUploadId(uuid, UploadId, isDisabled) {
179-
initUploadId.call(this);
180-
for (var i = uploadIdCache.length - 1; i >= 0; i--) {
181-
if (uploadIdCache[i][0] === uuid && uploadIdCache[i][1] === UploadId) {
182-
uploadIdCache.splice(i, 1);
183-
}
184-
}
185-
uploadIdCache.unshift([uuid, UploadId]);
186-
var cacheLimit = this.options.UploadIdCacheLimit;
187-
if (uploadIdCache.length > cacheLimit) {
188-
uploadIdCache.splice(cacheLimit);
189-
}
190-
cacheLimit && setTimeout(function () {
191-
try {
192-
localStorage.setItem(uploadIdCacheKey, JSON.stringify(uploadIdCache));
193-
} catch (e) {}
194-
});
195-
}
196-
function removeUploadId(UploadId) {
197-
initUploadId.call(this);
198-
delete uploadIdUsing[UploadId];
199-
for (var i = uploadIdCache.length - 1; i >= 0; i--) {
200-
if (uploadIdCache[i][1] === UploadId) {
201-
uploadIdCache.splice(i, 1)
202-
}
203-
}
204-
var cacheLimit = this.options.UploadIdCacheLimit;
205-
if (uploadIdCache.length > cacheLimit) {
206-
uploadIdCache.splice(cacheLimit);
207-
}
208-
cacheLimit && setTimeout(function () {
209-
try {
210-
if (uploadIdCache.length) {
211-
localStorage.setItem(uploadIdCacheKey, JSON.stringify(uploadIdCache));
212-
} else {
213-
localStorage.removeItem(uploadIdCacheKey);
214-
}
215-
} catch (e) {}
216-
});
217-
}
218-
function getUploadId(uuid) {
219-
initUploadId.call(this);
220-
var CacheUploadIdList = [];
221-
for (var i = 0; i < uploadIdCache.length; i++) {
222-
if (uploadIdCache[i][0] === uuid) {
223-
CacheUploadIdList.push(uploadIdCache[i][1]);
224-
}
225-
}
226-
return CacheUploadIdList.length ? CacheUploadIdList : null;
227-
}
228-
229156
// 获取上传任务的 UploadId
230157
function getUploadIdAndPartList(params, callback) {
231158
var TaskId = params.TaskId;
@@ -316,7 +243,7 @@ function getUploadIdAndPartList(params, callback) {
316243
});
317244

318245
// 存在 UploadId
319-
ep.on('upload_id_ready', function (UploadData) {
246+
ep.on('upload_id_available', function (UploadData) {
320247
// 转换成 map
321248
var map = {};
322249
var list = [];
@@ -364,18 +291,18 @@ function getUploadIdAndPartList(params, callback) {
364291
if (!UploadId) {
365292
return callback({Message: 'no upload id'});
366293
}
367-
ep.emit('upload_id_ready', {UploadId: UploadId, PartList: []});
294+
ep.emit('upload_id_available', {UploadId: UploadId, PartList: []});
368295
});
369296
});
370297

371298
// 如果已存在 UploadId,找一个可以用的 UploadId
372-
ep.on('has_upload_id', function (UploadIdList) {
299+
ep.on('has_and_check_upload_id', function (UploadIdList) {
373300
// 串行地,找一个内容一致的 UploadId
374301
UploadIdList = UploadIdList.reverse();
375302
Async.eachLimit(UploadIdList, 1, function (UploadId, asyncCallback) {
376303
if (!self._isRunningTask(TaskId)) return;
377304
// 如果正在上传,跳过
378-
if (uploadIdUsing[UploadId]) {
305+
if (session.using[UploadId]) {
379306
asyncCallback(); // 检查下一个 UploadId
380307
return;
381308
}
@@ -388,7 +315,7 @@ function getUploadIdAndPartList(params, callback) {
388315
}, function (err, PartListData) {
389316
if (!self._isRunningTask(TaskId)) return;
390317
if (err) {
391-
removeUploadId.call(self, UploadId);
318+
session.removeUsing(UploadId);
392319
return ep.emit('error', err);
393320
}
394321
var PartList = PartListData.PartList;
@@ -414,7 +341,7 @@ function getUploadIdAndPartList(params, callback) {
414341
if (!self._isRunningTask(TaskId)) return;
415342
onHashProgress(null, true);
416343
if (AvailableUploadData && AvailableUploadData.UploadId) {
417-
ep.emit('upload_id_ready', AvailableUploadData);
344+
ep.emit('upload_id_available', AvailableUploadData);
418345
} else {
419346
ep.emit('no_available_upload_id');
420347
}
@@ -424,50 +351,52 @@ function getUploadIdAndPartList(params, callback) {
424351
// 在本地缓存找可用的 UploadId
425352
ep.on('seek_local_avail_upload_id', function (RemoteUploadIdList) {
426353
// 在本地找可用的 UploadId
427-
var uuid = util.getFileUUID(params.Body, params.ChunkSize), LocalUploadIdList;
428-
if (uuid && (LocalUploadIdList = getUploadId.call(self, uuid))) {
429-
var next = function (index) {
430-
// 如果本地找不到可用 UploadId,再一个个遍历校验远端
431-
if (index >= LocalUploadIdList.length) {
432-
ep.emit('has_upload_id', RemoteUploadIdList);
433-
return;
434-
}
435-
var UploadId = LocalUploadIdList[index];
436-
// 如果不在远端 UploadId 列表里,跳过并删除
437-
if (!util.isInArray(RemoteUploadIdList, UploadId)) {
438-
removeUploadId.call(self, UploadId);
439-
next(index + 1);
440-
return;
441-
}
442-
// 如果正在上传,跳过
443-
if (uploadIdUsing[UploadId]) {
354+
var uuid = session.getFileId(params.Body, params.ChunkSize, Bucket, Key);
355+
var LocalUploadIdList = session.getUploadIdList(uuid);
356+
if (!uuid || !LocalUploadIdList) {
357+
ep.emit('has_and_check_upload_id', RemoteUploadIdList);
358+
return;
359+
}
360+
var next = function (index) {
361+
// 如果本地找不到可用 UploadId,再一个个遍历校验远端
362+
if (index >= LocalUploadIdList.length) {
363+
ep.emit('has_and_check_upload_id', RemoteUploadIdList);
364+
return;
365+
}
366+
var UploadId = LocalUploadIdList[index];
367+
// 如果不在远端 UploadId 列表里,跳过并删除
368+
if (!util.isInArray(RemoteUploadIdList, UploadId)) {
369+
session.removeUploadId(UploadId);
370+
next(index + 1);
371+
return;
372+
}
373+
// 如果正在上传,跳过
374+
if (session.using[UploadId]) {
375+
next(index + 1);
376+
return;
377+
}
378+
// 判断 UploadId 是否存在线上
379+
wholeMultipartListPart.call(self, {
380+
Bucket: Bucket,
381+
Region: Region,
382+
Key: Key,
383+
UploadId: UploadId,
384+
}, function (err, PartListData) {
385+
if (!self._isRunningTask(TaskId)) return;
386+
if (err) {
387+
// 如果 UploadId 获取会出错,跳过并删除
388+
session.removeUploadId(UploadId);
444389
next(index + 1);
445-
return;
390+
} else {
391+
// 找到可用 UploadId
392+
ep.emit('upload_id_available', {
393+
UploadId: UploadId,
394+
PartList: PartListData.PartList,
395+
});
446396
}
447-
// 判断 UploadId 是否存在线上
448-
wholeMultipartListPart.call(self, {
449-
Bucket: Bucket,
450-
Region: Region,
451-
Key: Key,
452-
UploadId: UploadId,
453-
}, function (err, PartListData) {
454-
if (!self._isRunningTask(TaskId)) return;
455-
if (err) {
456-
removeUploadId.call(self, UploadId);
457-
next(index + 1);
458-
} else {
459-
// 找到可用 UploadId
460-
ep.emit('upload_id_ready', {
461-
UploadId: UploadId,
462-
PartList: PartListData.PartList,
463-
});
464-
}
465-
});
466-
};
467-
next(0);
468-
} else {
469-
ep.emit('has_upload_id', RemoteUploadIdList);
470-
}
397+
});
398+
};
399+
next(0);
471400
});
472401

473402
// 获取线上 UploadId 列表
@@ -491,10 +420,11 @@ function getUploadIdAndPartList(params, callback) {
491420
if (RemoteUploadIdList.length) {
492421
ep.emit('seek_local_avail_upload_id', RemoteUploadIdList);
493422
} else {
494-
var uuid = util.getFileUUID(params.Body, params.ChunkSize), LocalUploadIdList;
495-
if (uuid && (LocalUploadIdList = getUploadId.call(self, uuid))) {
423+
// 远端没有 UploadId,清理缓存的 UploadId
424+
var uuid = session.getFileId(params.Body, params.ChunkSize, Bucket, Key), LocalUploadIdList;
425+
if (uuid && (LocalUploadIdList = session.getUploadIdList(uuid))) {
496426
util.each(LocalUploadIdList, function (UploadId) {
497-
removeUploadId.call(self, UploadId);
427+
session.removeUploadId(UploadId);
498428
});
499429
}
500430
ep.emit('no_available_upload_id');

src/base.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1611,9 +1611,8 @@ function restoreObject(params, callback) {
16111611
function multipartInit(params, callback) {
16121612

16131613
var self = this;
1614-
var headers = params.Headers;
1615-
16161614
// 特殊处理 Cache-Control
1615+
var headers = params.Headers;
16171616
!headers['Cache-Control'] && (headers['Cache-Control'] = '');
16181617
util.getBodyMd5(params.Body && (params.UploadAddMetaMd5 || self.options.UploadAddMetaMd5), params.Body, function (md5) {
16191618
if (md5) params.Headers['x-cos-meta-md5'] = md5;

src/session.js

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
var util = require('./util');
2+
3+
// 按照文件特征值,缓存 UploadId
4+
var cacheKey = 'cos_sdk_upload_cache';
5+
var expires = 30 * 24 * 3600;
6+
var cache;
7+
var timer;
8+
9+
var init = function () {
10+
if (cache) return;
11+
cache = JSON.parse(localStorage.getItem(cacheKey) || '[]') || [];
12+
// 清理太老旧的数据
13+
var changed = false;
14+
var now = Math.round(Date.now() / 1000);
15+
for (var i = cache.length - 1; i >= 0; i--) {
16+
var mtime = cache[i][2];
17+
if (!mtime || mtime + expires < now) {
18+
cache.splice(i, 1);
19+
changed = true;
20+
}
21+
}
22+
changed && localStorage.setItem(cacheKey, JSON.stringify(cache));
23+
};
24+
25+
// 把缓存存到本地
26+
var save = function () {
27+
if (timer) return;
28+
timer = setTimeout(function () {
29+
localStorage.setItem(cacheKey, JSON.stringify(cache));
30+
timer = null;
31+
}, 400);
32+
};
33+
34+
var mod = {
35+
using: {},
36+
// 标记 UploadId 正在使用
37+
setUsing: function (uuid) {
38+
mod.using[uuid] = true;
39+
},
40+
// 标记 UploadId 已经没在使用
41+
removeUsing: function (uuid) {
42+
delete mod.using[uuid];
43+
},
44+
// 用上传参数生成哈希值
45+
getFileId: function (file, ChunkSize, Bucket, Key) {
46+
if (file.name && file.size && file.lastModifiedDate && ChunkSize) {
47+
return util.md5([file.name, file.size, file.lastModifiedDate, ChunkSize, Bucket, Key].join('::'));
48+
} else {
49+
return null;
50+
}
51+
},
52+
// 获取文件对应的 UploadId 列表
53+
getUploadIdList: function (uuid) {
54+
if (!uuid) return null;
55+
init();
56+
var list = [];
57+
for (var i = 0; i < cache.length; i++) {
58+
if (cache[i][0] === uuid)
59+
list.push(cache[i][1]);
60+
}
61+
return list.length ? list : null;
62+
},
63+
// 缓存 UploadId
64+
saveUploadId: function (uuid, UploadId, limit) {
65+
init();
66+
if (!uuid) return;
67+
// 清理没用的 UploadId
68+
for (var i = cache.length - 1; i >= 0; i--) {
69+
var item = cache[i];
70+
if (item[0] === uuid && item[1] === UploadId) {
71+
cache.splice(i, 1);
72+
}
73+
}
74+
cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]);
75+
if (cache.length > limit) cache.splice(limit);
76+
save();
77+
},
78+
// UploadId 已用完,移除掉
79+
removeUploadId: function (UploadId) {
80+
init();
81+
delete mod.using[UploadId];
82+
for (var i = cache.length - 1; i >= 0; i--) {
83+
if (cache[i][1] === UploadId) cache.splice(i, 1)
84+
}
85+
save();
86+
},
87+
};
88+
89+
module.exports = mod;

0 commit comments

Comments
 (0)