Skip to content

Commit 72469b4

Browse files
wangxiaoleeyeh
authored andcommitted
Upload file in U.S. region by fileToken and s3. (#310)
* Upload file in U.S. region by fileToken and s3. * Remove the abroad branch of upload file * fix the s3 upload function
1 parent 45e106a commit 72469b4

File tree

6 files changed

+88
-105
lines changed

6 files changed

+88
-105
lines changed

.eslintrc.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
module.exports = {
22
extends: 'airbnb',
3+
env: {
4+
node: true,
5+
mocha: true,
6+
browser: true,
7+
},
38
rules: {
49
'no-param-reassign': 0,
510
'no-underscore-dangle': 0,
@@ -9,5 +14,7 @@ module.exports = {
914
'no-console': [ 2, { allow: ['warn', 'trace'] } ],
1015
'no-restricted-syntax': [ 0, 'ForInStatement' ],
1116
'no-new': 0,
17+
'new-cap': 0,
18+
'default-case': 0,
1219
}
1320
};

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ JavaScript SDK for [LeanCloud](http://leancloud.cn/).
1717
* `npm install` 安装相关依赖
1818
* 开发和调试
1919
* 浏览器环境执行 `gulp dev`,会自动启动 `demo` 目录,可在 `test-es6.js` 中修改和测试,`test-es5.js` 为自动生成的代码
20-
* Nodejs 环境可以在 `demo/node` 目录中,通过执行 `node test.js` 使用 `test.js` 文件开发与调试。推荐安装 `node inspector` 来调试,安装后执行 `node-debug test.js`。每次修改代码后,如果开发代码引用的是 dist 目录中的代码,需要执行 `gulp release`
20+
* Nodejs 环境同样在 `demo` 目录中,通过执行 `node test-es6.js` 开发与调试。推荐安装 `node inspector` 来调试,安装后执行 `node-debug test-es6.js`。每次修改代码后,如果开发代码引用的是 dist 目录中的代码,需要执行 `gulp release`
2121
* 确保测试全部通过 `gulp test`,浏览器环境打开 `test/test.html`
2222
* 提交并发起 `Pull Request`
2323
* 执行 `gulp release` 会生成全部版本的 SDK

demo/node/test.js

Lines changed: 0 additions & 41 deletions
This file was deleted.

demo/test-es6.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,26 @@
66
/* eslint no-console: ["error", { allow: ["log"] }] */
77
/* eslint no-undef: ["error", { "AV": true }] */
88

9+
'use strict';
10+
11+
let global = global || window;
12+
let AV = global.AV || {};
13+
14+
// 检测是否在 Nodejs 环境下运行
15+
if (typeof(process) !== 'undefined' && process.versions && process.versions.node) {
16+
AV = require('../dist/node/av');
17+
}
18+
919
// 初始化
1020
const appId = 'a5CDnmOX94uSth8foK9mjHfq-gzGzoHsz';
1121
const appKey = 'Ue3h6la9zH0IxkUJmyhLjk9h';
12-
const AV = AV || {};
22+
const region = 'cn';
23+
24+
// const appId = 'QvNM6AG2khJtBQo6WRMWqfLV-gzGzoHsz';
25+
// const appKey = 'be2YmUduiuEnCB2VR9bLRnnV';
26+
// const region = 'us';
1327

14-
AV.init({ appId, appKey });
28+
AV.init({ appId, appKey, region });
1529

1630
// 基本存储
1731
const TestClass = AV.Object.extend('TestClass');
@@ -32,8 +46,8 @@ testObj.save().then(() => {
3246
const base64 = 'd29ya2luZyBhdCBhdm9zY2xvdWQgaXMgZ3JlYXQh';
3347
const file = new AV.File('myfile.txt', { base64 });
3448
file.metaData('format', 'txt file');
35-
file.save().then((data) => {
36-
console.log(data);
49+
file.save().then(() => {
50+
console.log(file.get('url'));
3751
}).catch((error) => {
3852
console.log(error);
3953
});

src/file.js

Lines changed: 31 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
const _ = require('underscore');
77
const cos = require('./uploader/cos');
88
const qiniu = require('./uploader/qiniu');
9+
const s3 = require('./uploader/s3');
910
const AVError = require('./error');
1011
const AVRequest = require('./request').request;
1112

@@ -618,20 +619,19 @@ module.exports = function(AV) {
618619
* @return {AV.Promise} Resolved with the response
619620
* @private
620621
*/
621-
_fileToken: function(type, route = 'fileTokens') {
622+
_fileToken(type, route = 'fileTokens') {
622623
const name = this.attributes.name;
623-
//Create 16-bits uuid as qiniu key.
624+
625+
// Create 16-bits uuid as qiniu key.
624626
const extName = extname(name);
625-
const hexOctet = function() {
626-
return Math.floor((1+Math.random())*0x10000).toString(16).substring(1);
627-
};
627+
const hexOctet = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
628628
const key = hexOctet() + hexOctet() + hexOctet() + hexOctet() + hexOctet() + extName;
629629
const data = {
630-
key: key,
630+
key,
631+
name,
631632
ACL: this._acl,
632-
name: name,
633633
mime_type: type,
634-
metaData: this.attributes.metaData
634+
metaData: this.attributes.metaData,
635635
};
636636
if (type && !this.attributes.metaData.mime_type) {
637637
this.attributes.metaData.mime_type = type;
@@ -651,7 +651,7 @@ module.exports = function(AV) {
651651
* @param {Object} options A Backbone-style options object.
652652
* @return {AV.Promise} Promise that is resolved when the save finishes.
653653
*/
654-
save: function(...args) {
654+
save(...args) {
655655
if (this.id) {
656656
throw new Error('File already saved. If you want to manipulate a file, use AV.Query to get it.');
657657
}
@@ -660,41 +660,45 @@ module.exports = function(AV) {
660660
switch (args.length) {
661661
case 1:
662662
options = args[0];
663-
break;
663+
break;
664664
case 2:
665665
saveOptions = args[0];
666666
options = args[1];
667-
break;
667+
break;
668668
}
669669
if (!this._previousSave) {
670-
// 如果是国内节点
671-
var isCnNodeFlag = isCnNode();
672-
if (this._source && isCnNodeFlag) {
673-
// 通过国内 CDN 服务商上传
674-
this._previousSave = this._source.then((data, type) => {
675-
return this._fileToken(type).catch(() => this._fileToken(type, 'qiniu'))
670+
if (this._source) {
671+
this._previousSave = this._source.then((data, type) =>
672+
this._fileToken(type)
676673
.then(uploadInfo => {
677674
let uploadPromise;
678-
if (uploadInfo.provider === 'qcloud') {
679-
uploadPromise = cos(uploadInfo, data, this, saveOptions);
680-
} else {
681-
uploadPromise = qiniu(uploadInfo, data, this, saveOptions);
675+
switch (uploadInfo.provider) {
676+
case 's3':
677+
uploadPromise = s3(uploadInfo, data, this, saveOptions);
678+
break;
679+
case 'qcloud':
680+
uploadPromise = cos(uploadInfo, data, this, saveOptions);
681+
break;
682+
case 'qiniu':
683+
default:
684+
uploadPromise = qiniu(uploadInfo, data, this, saveOptions);
685+
break;
682686
}
683687
return uploadPromise.catch(err => {
684-
//destroy this file object when upload fails.
688+
// destroy this file object when upload fails.
685689
this.destroy();
686690
throw err;
687691
});
688-
});
689-
});
692+
})
693+
);
690694
} else if (this.attributes.url && this.attributes.metaData.__source === 'external') {
691-
//external link file.
692-
var data = {
695+
// external link file.
696+
const data = {
693697
name: this.attributes.name,
694698
ACL: this._acl,
695699
metaData: this.attributes.metaData,
696700
mime_type: this._guessedType,
697-
url: this.attributes.url
701+
url: this.attributes.url,
698702
};
699703
this._previousSave = AVRequest('files', this.attributes.name, null, 'post', data).then((response) => {
700704
this.attributes.name = response.name;
@@ -705,38 +709,6 @@ module.exports = function(AV) {
705709
}
706710
return this;
707711
});
708-
} else if (!isCnNodeFlag) {
709-
// 海外节点,通过 LeanCloud 服务器中转
710-
this._previousSave = this._source.then((file, type) => {
711-
var data = {
712-
base64: '',
713-
_ContentType: type,
714-
ACL: this._acl,
715-
mime_type: type,
716-
metaData: this.attributes.metaData,
717-
};
718-
// 判断是否数据已经是 base64
719-
if (this.attributes.base64) {
720-
data.base64 = this.attributes.base64;
721-
return AVRequest('files', this.attributes.name, null, 'POST', data);
722-
} else if (typeof global.Buffer !== "undefined" && global.Buffer.isBuffer(file)) {
723-
data.base64 = file.toString('base64');
724-
return AVRequest('files', this.attributes.name, null, 'POST', data);
725-
} else {
726-
return readAsync(file).then(function(base64) {
727-
data.base64 = base64;
728-
return AVRequest('files', this.attributes.name, null, 'POST', data);
729-
});
730-
}
731-
}).then((response) => {
732-
this.attributes.name = response.name;
733-
this.attributes.url = response.url;
734-
this.id = response.objectId;
735-
if (response.size) {
736-
this.attributes.metaData.size = response.size;
737-
}
738-
return this;
739-
});
740712
}
741713
}
742714
return this._previousSave._thenRunCallbacks(options);

src/uploader/s3.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* 每位工程师都有保持代码优雅的义务
3+
* Each engineer has a duty to keep the code elegant
4+
**/
5+
6+
const request = require('superagent');
7+
const AVPromise = require('../promise');
8+
9+
module.exports = function upload(uploadUrl, data, file, saveOptions = {}) {
10+
// 海外节点,针对 S3 才会返回 upload_url
11+
file.attributes.url = uploadInfo.url;
12+
const promise = new AVPromise();
13+
const req = request('PUT', uploadUrl)
14+
.set('Content-Type', file.attributes.metaData.mime_type)
15+
.send(data)
16+
.end((err, res) => {
17+
if (err) {
18+
if (res) {
19+
err.statusCode = res.status;
20+
err.responseText = res.text;
21+
err.response = res.body;
22+
}
23+
return promise.reject(err);
24+
}
25+
promise.resolve(file);
26+
});
27+
if (saveOptions.onprogress) {
28+
req.on('progress', saveOptions.onprogress);
29+
}
30+
return promise;
31+
};

0 commit comments

Comments
 (0)