You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
6.7 KiB
267 lines
6.7 KiB
(function(win) { |
|
function forEach(m, callback) { |
|
for (var key in m) { |
|
callback(key, m[key]); |
|
} |
|
} |
|
|
|
function buildUrl(url, items) { |
|
var query = ''; |
|
forEach(items, function(name, value) { |
|
if (name != 'token') { |
|
query += (query ? '&' : '') + encodeURIComponent(name) + '=' + encodeURIComponent(value); |
|
} |
|
}); |
|
|
|
if (query) { |
|
url += (url.indexOf('?') > 0 ? '&' : '?') + query; |
|
} |
|
|
|
return url; |
|
} |
|
|
|
function encode2UTF8(argString) { |
|
if (argString === null || typeof argString === 'undefined') { |
|
return ''; |
|
} |
|
var string = (argString + ''); // .replace(/\r\n/g, '\n').replace(/\r/g, '\n'); |
|
var utftext = '', |
|
start, end, stringl = 0; |
|
start = end = 0; |
|
stringl = string.length; |
|
for (var n = 0; n < stringl; n++) { |
|
var c1 = string.charCodeAt(n); |
|
var enc = null; |
|
|
|
if (c1 < 128) { |
|
end++; |
|
} else if (c1 > 127 && c1 < 2048) { |
|
enc = String.fromCharCode( |
|
(c1 >> 6) | 192, (c1 & 63) | 128 |
|
); |
|
} else if (c1 & 0xF800 ^ 0xD800 > 0) { |
|
enc = String.fromCharCode( |
|
(c1 >> 12) | 224, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128 |
|
); |
|
} else { // surrogate pairs |
|
if (c1 & 0xFC00 ^ 0xD800 > 0) { |
|
throw new RangeError('Unmatched trail surrogate at ' + n); |
|
} |
|
var c2 = string.charCodeAt(++n); |
|
if (c2 & 0xFC00 ^ 0xDC00 > 0) { |
|
throw new RangeError('Unmatched lead surrogate at ' + (n - 1)); |
|
} |
|
c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000; |
|
enc = String.fromCharCode( |
|
(c1 >> 18) | 240, ((c1 >> 12) & 63) | 128, ((c1 >> 6) & 63) | 128, (c1 & 63) | 128 |
|
); |
|
} |
|
if (enc !== null) { |
|
if (end > start) { |
|
utftext += string.slice(start, end); |
|
} |
|
utftext += enc; |
|
start = end = n + 1; |
|
} |
|
} |
|
|
|
if (end > start) { |
|
utftext += string.slice(start, stringl); |
|
} |
|
|
|
return utftext; |
|
} |
|
// Copy 七牛 SDK 方法 |
|
function encode2Base64(data) { |
|
var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; |
|
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, |
|
ac = 0, |
|
enc = '', |
|
tmp_arr = []; |
|
|
|
if (!data) { |
|
return data; |
|
} |
|
|
|
data = encode2UTF8(data + ''); |
|
|
|
do { // pack three octets into four hexets |
|
o1 = data.charCodeAt(i++); |
|
o2 = data.charCodeAt(i++); |
|
o3 = data.charCodeAt(i++); |
|
|
|
bits = o1 << 16 | o2 << 8 | o3; |
|
|
|
h1 = bits >> 18 & 0x3f; |
|
h2 = bits >> 12 & 0x3f; |
|
h3 = bits >> 6 & 0x3f; |
|
h4 = bits & 0x3f; |
|
|
|
// use hexets to index into b64, and append result to encoded string |
|
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); |
|
} while (i < data.length); |
|
|
|
enc = tmp_arr.join(''); |
|
|
|
switch (data.length % 3) { |
|
case 1: |
|
enc = enc.slice(0, -2) + '=='; |
|
break; |
|
case 2: |
|
enc = enc.slice(0, -1) + '='; |
|
break; |
|
} |
|
return enc; |
|
} |
|
// Copy 七牛 SDK 方法 |
|
function URLSafeBase64Encode(v) { |
|
v = encode2Base64(v); |
|
return v.replace(/\//g, '_').replace(/\+/g, '-'); |
|
} |
|
|
|
function chunkLastStep(data, opts, callback) { |
|
// 七牛 URL 规定 |
|
var key = '/key/' + URLSafeBase64Encode(data.filename); |
|
var fname = '/fname/' + URLSafeBase64Encode(data.filename); |
|
var url = opts.domain + '/mkfile/' + data.size + key + fname; |
|
var options = { |
|
domain: url, |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/octet-stream' |
|
}, |
|
multi_parmas: opts.multi_parmas, |
|
support_options: true, |
|
stream: true |
|
}; |
|
uploadData(data.ctx, options, { |
|
onCompleted: function(res) { |
|
res.filename = data.filename; |
|
res.name = data.name; |
|
callback.onCompleted(res); |
|
}, |
|
onError: function() { |
|
throw new Error('qiniu uploadChunk error'); |
|
}, |
|
onProgress: function(chunkLoaded, total) {}, |
|
onOpen: function(xhr) { |
|
callback.onOpen(xhr); |
|
} |
|
}); |
|
} |
|
|
|
var offset = 0, |
|
ctxStore = {}; |
|
|
|
function uploadNextChunk(blob, opts, callback) { |
|
var chunk = Math.ceil(offset / opts.chunk_size), |
|
chunks = Math.ceil(blob.size / opts.chunk_size), |
|
curChunkSize = Math.min(opts.chunk_size, blob.size - offset), |
|
chunkBlob = blob.slice(offset, offset + curChunkSize), |
|
chunkInfo = { |
|
chunk: chunk, |
|
chunks: chunks, |
|
name: blob.uniqueName |
|
}; |
|
forEach(chunkInfo, function(key, value) { |
|
opts.multi_parmas[key] = value; |
|
}); |
|
opts.filesize = blob.size; |
|
opts.headers = { |
|
'Content-Type': 'application/octet-stream' |
|
}; |
|
opts.isChunk = true; |
|
uploadData(chunkBlob, opts, { |
|
onCompleted: function(chunkRes) { |
|
offset += curChunkSize; |
|
// callback.onProgress(Math.floor((chunk + 1) / chunks * blob.size), blob.size); |
|
ctxStore[blob.uniqueName] = ctxStore[blob.uniqueName] || []; |
|
ctxStore[blob.uniqueName].push(chunkRes.ctx); |
|
if (offset < blob.size) { |
|
if (chunkRes.ctx) { |
|
uploadNextChunk(blob, opts, callback); |
|
}else{ |
|
offset = 0; |
|
delete ctxStore[blob.uniqueName] |
|
} |
|
} else { |
|
offset = 0; |
|
delete opts.isChunk; |
|
delete opts.headers['Content-Type']; |
|
forEach(chunkInfo, function(key, value) { |
|
delete opts.multi_parmas[key]; |
|
}); |
|
var ctx = ctxStore[blob.uniqueName].join(','); |
|
var data = { |
|
ctx: ctx, |
|
name: blob.name, |
|
size: blob.size, |
|
filename: blob.uniqueName |
|
}; |
|
chunkLastStep(data, opts, callback); |
|
} |
|
}, |
|
onError: function() { |
|
throw new Error('qiniu uploadChunk error'); |
|
}, |
|
onProgress: function(chunkLoaded, total) { |
|
var loaded = chunkLoaded + offset; |
|
callback.onProgress(loaded, opts.filesize); |
|
}, |
|
onOpen: function(xhr) { |
|
callback.onOpen(xhr); |
|
} |
|
}); |
|
} |
|
|
|
function uploadData(data, options, callback) { |
|
var xhr = new XMLHttpRequest(); |
|
if (xhr.upload && options.support_options) { |
|
xhr.upload.onprogress = function(event) { |
|
callback.onProgress(event.loaded, event.total); |
|
}; |
|
} |
|
|
|
xhr.onreadystatechange = function() { |
|
if (xhr.readyState == 4) { |
|
var result = xhr.responseText || "{}"; |
|
result = JSON.parse(result); |
|
result.filename = options.unique_value; |
|
callback.onCompleted(result); |
|
} |
|
}; |
|
|
|
var url = options.domain; |
|
if (options.isChunk) { |
|
url += '/mkblk/' + data.size; |
|
url = buildUrl(url, options.multi_parmas); |
|
} |
|
xhr.open(options.method, url, true); |
|
|
|
callback.onOpen(xhr); |
|
|
|
if (options.stream) { |
|
xhr.setRequestHeader('authorization', 'UpToken ' + options.multi_parmas.token); |
|
} |
|
|
|
forEach(options.headers, function(key, value) { |
|
xhr.setRequestHeader(key, value); |
|
}); |
|
xhr.send(data); |
|
} |
|
|
|
function uploadQiniu(file, opts, callback) { |
|
if (file.size && opts.chunk_size < file.size) { |
|
var uniqueName = opts['genUId'](file); |
|
var suffix = file.name.substr(file.name.lastIndexOf('.')); |
|
uniqueName = uniqueName + suffix; |
|
file.uniqueName = uniqueName; |
|
opts.stream = true; |
|
uploadNextChunk(file, opts, callback); |
|
} else { |
|
var data = opts['data'](file, opts); |
|
uploadData(data, opts, callback); |
|
} |
|
} |
|
win.uploadProcess = uploadQiniu; |
|
})(window); |