ks3.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. (function KS3_UPLOAD(win) {
  2. var JSY={
  3. host:'http://ks3-cn-beijing.ksyun.com/teaseyoulearn',
  4. fileToBeUpload:'',
  5. };
  6. JSY.Config=function(opt){
  7. var opt=opt || {};
  8. Ks3.config.AK = opt.ak || '+vB0RuO22DeeanAAb0ig'; //TODO: 请替换为您的AK
  9. Ks3.config.SK = opt.sk || '3kbTp8pg+LymO84/ZyxG/od/3FeVDjWt+8/m5iBc'; //TODO: 测试时请填写您的secret key
  10. Ks3.config.region = 'BEIJING'; //TODO: 需要设置bucket所在region, 如杭州region: HANGZHOU,北京region:BEIJING,香港region:HONGKONG,上海region: SHANGHAI ,美国region:AMERICA ;如果region设置和实际不符,则会返回301状态码; region的endpoint参见:http://ks3.ksyun.com/doc/api/index.html
  11. Ks3.config.bucket = opt.bucket_name || 'teaseyoulearn'; // TODO : 设置默认bucket name
  12. Ks3.config.protocol=window.location.protocol === 'https:' ? 'https' : 'http';
  13. Ks3.config.baseUrl=Ks3.ENDPOINT[Ks3.config.region];
  14. window.Ks3Host=Ks3.config.protocol + '://' + Ks3.config.baseUrl+ '/' + Ks3.config.bucket;
  15. }
  16. JSY.upload=function(opt,successFn,errorFn){
  17. var opt=opt || {};
  18. var ks3Options = {
  19. KSSAccessKeyId: Ks3.config.AK,
  20. signature: opt.signature || '',
  21. bucket_name: Ks3.config.bucket,
  22. key: (opt.dirname || 'image')+'/${filename}',
  23. acl: "public-read",
  24. uploadDomain: Ks3.config.protocol + '://' + Ks3.config.baseUrl+ '/' + Ks3.config.bucket,
  25. autoStart: opt.autoStart || true,
  26. onFilesAddedCallBack:function (uploader,obj) {
  27. opt.FileAdd && opt.FileAdd(uploader,obj);
  28. },
  29. onErrorCallBack:function (uploader, errObject) {
  30. errorFn && errorFn(uploader,errObject);
  31. },
  32. onFileUploadedCallBack:function (uploader,obj) {
  33. successFn && successFn(uploader,obj);
  34. }
  35. };
  36. var uploader=new ks3FileUploader(ks3Options,{
  37. browse_button:opt.browse_button || 'browse',
  38. flash_swf_url :'/public/pc/ks3-js-sdk/src/Moxie.swf',
  39. silverlight_xap_url : '/public/pc/ks3-js-sdk/src/Moxie.xap',
  40. filters:{
  41. mime_types:[
  42. { title : "Image files", extensions : "jpg,gif,png" },
  43. { title : "Video files", extensions : "mp4,mov,qt,ts,rmvb,rm,avi,flv,mkv,wmv,mpg,mpeg,m2v,m4v,3gp,3g2,webm,vob,ogv,ogg" }
  44. ],
  45. prevent_duplicates:true,
  46. max_file_size:'2gb',
  47. },
  48. multi_selection:opt.max_length || false,
  49. });
  50. return uploader;
  51. }
  52. JSY.LoadEvent=function(){
  53. $('.upload-image-box').on({
  54. mouseover:function () {
  55. $(this).find('.mask').show();
  56. },
  57. mouseout:function () {
  58. $(this).find('.mask').hide();
  59. }
  60. })
  61. $('.open_image').on('click',function () {
  62. $eb.openImage($(this).data('url'));
  63. });
  64. }
  65. JSY.getImgBoxHtml=function ($name,inputname) {
  66. var host=this.host+'/'+$name,inputname=inputname || 'image';
  67. return '<div class="upload-image-box">\n' +
  68. ' <img src="'+host+'" alt="">\n' +
  69. ' <input type="hidden" name="'+inputname+'" value="'+host+'">\n' +
  70. ' <div class="mask">\n' +
  71. ' <p><i class="fa fa-eye open_image" data-url="'+host+'"></i><i class="fa fa-trash-o delete_image" data-url="'+$name+'"></i></p>\n' +
  72. ' </div>\n' +
  73. '</div>';
  74. };
  75. JSY.delObjectKey=function (keyArray) {
  76. $.each(keyArray,function (key) {
  77. delete keyArray[key];
  78. });
  79. }
  80. /**
  81. * 获取指定的文件部分内容
  82. */
  83. JSY.getFileContent=function(file, chunkSize, start, cb) {
  84. var start = start;
  85. var bufferSize = file.size;
  86. var index = start / chunkSize;
  87. console.log('正在读取下一个块的文件内容 index:' + index);
  88. if (start + chunkSize > bufferSize) {
  89. chunkSize = bufferSize - start;
  90. }
  91. console.log('分块大小:', chunkSize);
  92. if(file.slice) {
  93. var blob = file.slice(start, start + Ks3.config.chunkSize);
  94. }else if(file.webkitSlice) {
  95. var blob = file.webkitSlice(start, start + Ks3.config.chunkSize);
  96. }else if(file.mozSlice) {
  97. var blob = file.mozSlice(start, start + Ks3.config.chunkSize);
  98. }else{
  99. throw new Error("blob API doesn't work!");
  100. }
  101. var reader = new FileReader();
  102. reader.onload = function(e) {
  103. cb(e.target.result);
  104. };
  105. reader.readAsArrayBuffer(blob);
  106. }
  107. JSY.getProgressKey=function(name, lastModified, bucket, key) {
  108. return name + "-" + lastModified + "-" + bucket + "-" + key;
  109. }
  110. JSY.configInit=function (file, progressKey,successFn) {
  111. var fileSize = file.size;
  112. var count = parseInt(fileSize / Ks3.config.chunkSize) + ((fileSize % Ks3.config.chunkSize == 0 ? 0: 1));
  113. if (count == 0){
  114. successFn && successFn({msg: 'The file is empty.'})
  115. }else {
  116. config = {
  117. name: file.name,
  118. size: fileSize,
  119. chunkSize: Ks3.config.chunkSize,
  120. count:count,
  121. index: 1,
  122. etags:{},
  123. retries: 0
  124. }
  125. localStorage.setItem(progressKey, JSON.stringify(config));
  126. successFn && successFn();
  127. }
  128. }
  129. //分片上传
  130. JSY.multipartUpload=function (opt) {
  131. var file = opt.File,key=opt.key || '',totalSize = file.size,that=this,changeVal=opt.changeVal || null,
  132. successFn=opt.success || null,errorFn=opt.error || null,contentType = opt.ContentType || '';
  133. var progressKey =this.getProgressKey(file.name, file.lastModified,Ks3.config.bucket, key);
  134. async.auto({
  135. /**
  136. * 初始化配置文件,如果没有就新建一个
  137. */
  138. init: function(callback) {
  139. //重置暂停标识
  140. Ks3.config.stopFlag = false;
  141. if ( !localStorage[progressKey]) {
  142. that.configInit(file, progressKey, function(err) {
  143. callback(err);
  144. })
  145. } else {
  146. callback(null);
  147. }
  148. },
  149. show: ['init', function(callback) {
  150. console.log(' 开始上传文件: ' + progressKey);
  151. config = JSON.parse(localStorage.getItem(progressKey));
  152. changeVal && changeVal(config);
  153. callback(null);
  154. }],
  155. /**
  156. * 获取uploadId,如果有就直接读取,没有就从服务器获取一个
  157. */
  158. getUploadId: ['init', function(callback) {
  159. config = JSON.parse(localStorage.getItem(progressKey));
  160. var uploadId = config['uploadId'];
  161. if ( !! uploadId) {
  162. callback(null, uploadId);
  163. } else {
  164. Ks3.multitpart_upload_init(opt, function(err, uploadId) {
  165. if(err) {
  166. callback(err);
  167. }else {
  168. config['uploadId'] = uploadId;
  169. localStorage.setItem(progressKey, JSON.stringify(config));
  170. callback(null, uploadId);
  171. }
  172. });
  173. }
  174. }],
  175. /**
  176. * 对文件进行上传
  177. * 上传后要把信息写到本地存储配置文件中
  178. * 如果都上传完了,就把相关本地存储信息删除
  179. * 并通知服务器,合并分块文件
  180. */
  181. upload: ['getUploadId', function(callback, result) {
  182. if(result.getUploadId) {
  183. var uploadId = result.getUploadId;
  184. Ks3.config.currentUploadId = uploadId;
  185. config = JSON.parse(localStorage.getItem(progressKey));
  186. var count = config['count'];
  187. var index = config['index'];
  188. var chunkSize = config['chunkSize'];
  189. var currentRetries = config['retries'];
  190. up();
  191. }else {
  192. callback({'msg':'no uploadId'});
  193. }
  194. // 在报错的时候重试
  195. function retry(err) {
  196. console.log('upload ERROR:', err);
  197. if (currentRetries > Ks3.config.retries) {
  198. errorFn && errorFn(err);
  199. } else {
  200. currentRetries = currentRetries + 1;
  201. config['retries'] = currentRetries;
  202. localStorage.setItem(progressKey, JSON.stringify(config));
  203. console.log('第 ' + currentRetries + ' 次重试');
  204. up();
  205. }
  206. }
  207. // 真正往服务端传递数据
  208. function up() {
  209. console.log('正在上传 ', 'index: ' + index);
  210. var start = (index - 1) * chunkSize;
  211. // 判断是否已经全部都传完了
  212. if (index <= count) {
  213. that.getFileContent(file, chunkSize, start, function(body) {
  214. delete opt.File;
  215. opt.UploadId = uploadId;
  216. opt.PartNumber = index;
  217. opt.body = body;
  218. opt.type = contentType;
  219. console.log('正在上传第 ', index, ' 块,总共: ', + count + ' 块');
  220. try {
  221. Ks3.upload_part(opt, function(err, partNumber, etag) {
  222. if (err) {
  223. if(err.status == 413 || err.status == 415) {
  224. callback(err);
  225. }else {
  226. retry(err);
  227. }
  228. } else {
  229. if(!Ks3.config.stopFlag) {
  230. config['index'] = index;
  231. changeVal && changeVal(config);
  232. config['etags'][index] = etag;
  233. localStorage.setItem(progressKey, JSON.stringify(config));
  234. index = index + 1;
  235. up();
  236. }else {
  237. callback({
  238. msg: "stop"
  239. });
  240. }
  241. }
  242. });
  243. } catch(e) {
  244. retry(e);
  245. }
  246. })
  247. } else {
  248. console.log('发送合并请求');
  249. delete opt.File;
  250. opt.UploadId = uploadId;
  251. opt.body = that.generateCompleteXML(progressKey);
  252. Ks3.upload_complete(opt, function(err, res) {
  253. if (err) throw err;
  254. callback(err, res);
  255. })
  256. }
  257. };
  258. }]
  259. },function(err, results) {
  260. if (!err) localStorage.removeItem(progressKey);
  261. if(err) errorFn && errorFn(err);
  262. else successFn && successFn(results);
  263. });
  264. }
  265. /**
  266. * 生成合并分块上传使用的xml
  267. */
  268. JSY.generateCompleteXML=function(progressKey) {
  269. var content = JSON.parse(localStorage.getItem(progressKey));
  270. var index = content.index;
  271. var str = '';
  272. if (index > 0) {
  273. str = '<CompleteMultipartUpload>';
  274. for (var i = 1; i <= index; i++) {
  275. str += '<Part><PartNumber>' + i + '</PartNumber><ETag>' + content.etags[i] + '</ETag></Part>'
  276. }
  277. str += '</CompleteMultipartUpload>';
  278. }
  279. return str;
  280. }
  281. //暂停
  282. JSY.suspendMultipartUpload=function () {
  283. Ks3.config.stopFlag = true;
  284. }
  285. //清除localStorage
  286. JSY.emptyLocalStorage=function(){
  287. var len = localStorage.length;
  288. for(var i=0; i< len; i++) {
  289. var itemKey = localStorage.key(i);
  290. //自动创建一个临时String对象封装itemKey在IE下会导致内存泄露,故显示转换
  291. if(typeof itemKey === 'string' && (new String(itemKey)).endWith(Ks3.config.bucket + '-' + Ks3.encodeKey(this.fileToBeUpload))) {
  292. localStorage.removeItem(itemKey);
  293. }
  294. }
  295. }
  296. //取消上传
  297. JSY.cancelMultipartUpload=function (findFn) {
  298. var that=this;
  299. //前端暂停
  300. Ks3.config.stopFlag = true;
  301. //通知ks3取消上传
  302. if(Ks3.config.currentUploadId) {
  303. Ks3.abort_multipart_upload({
  304. Bucket:Ks3.config.bucket,
  305. Key:this.fileToBeUpload,
  306. UploadId: Ks3.config.currentUploadId
  307. },function(err,res) {
  308. if(err) {
  309. findFn && findFn(err);
  310. }else{
  311. findFn && findFn(err);
  312. that.emptyLocalStorage();
  313. }
  314. });
  315. }
  316. }
  317. return win.JSY=JSY;
  318. })(window)